{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 3065,
     "status": "ok",
     "timestamp": 1734596624098,
     "user": {
      "displayName": "yuzhen",
      "userId": "05774191734922144334"
     },
     "user_tz": -480
    },
    "id": "unXi9LK2f999",
    "outputId": "67d125ac-7eb7-4fbf-8cb6-64305f8c83a3"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current\n",
      "                                 Dload  Upload   Total   Spent    Left  Speed\n",
      "100  3719  100  3719    0     0   2913      0  0:00:01  0:00:01 --:--:--  2914\n",
      "Archive:  ossutil-linux-amd64.zip\n",
      "   creating: tmp_unzip_dir_for_ossutil/ossutil-linux-amd64/\n",
      "  inflating: tmp_unzip_dir_for_ossutil/ossutil-linux-amd64/ossutil  [binary]\n",
      "  inflating: tmp_unzip_dir_for_ossutil/ossutil-linux-amd64/ossutil64  [binary]\n",
      "\n",
      "ossutil version: v1.7.19 has successfully installed.\n",
      "Now run \"ossutil config\" for setup. Check https://help.aliyun.com/document_detail/50452.html for more details.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 安装ossutil\n",
    "!curl https://gosspublic.alicdn.com/ossutil/install.sh | bash"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 1110,
     "status": "ok",
     "timestamp": 1734596634020,
     "user": {
      "displayName": "yuzhen",
      "userId": "05774191734922144334"
     },
     "user_tz": -480
    },
    "id": "vgrsXMNIgSis",
    "outputId": "e2dae31e-31c7-4492-f7c2-4a79688ac504"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\rSucceed: Total num: 1, size: 291,359. OK num: 1(download 1 objects).\n",
      "\n",
      "average speed 236000(byte/s)\n",
      "\n",
      "1.230781(s) elapsed\n"
     ]
    }
   ],
   "source": [
    "!ossutil cp oss://tianchi-race-prod-sh/file/race/documents/532220/annotations.zip ./annotations.zip -i STS.NTxtvdZpxFQJQ1aWNT4SG6USM -k xPgEdvTPunoew46iN3FPAZhKbCpB2a8RgiHWS1jRrnD --endpoint=oss-cn-shanghai.aliyuncs.com --sts-token=CAISrAN1q6Ft5B2yfSjIr5fNP8zQt69Z8ZOhUxfQs04BONxr2ZD4rzz2IHhPfHlpAe0Zs/Q/nWpW6PYclrhvQKhJTFDNacJ62ckMq1n7O9IMQDFeO+ZW5qe+EE2/VjQxta27OpcNJbGwU/OpbE++2U0X6LDmdDKkckW4OJmS8/BOZcgWWQ/KClgjA8xNdCRvtOgQN3baKYyvUHjQj3HXEVBjtydllGp78t7f+MCH7QfEh1CI7I0xro/qcJ+/dJsubtUtT9a82ud2d+/b2SVdrgBQ86szl6wD9zbDs5aHClJcpBmBOPfR/9tzN0gkPfJgQfYDpf76kuFxpu3UkZ+x2RdVf8MtCniGHdDxn5OdQLL3aItpKIyWYSqdjoq9UbDuqB4hbH4hMwdHRsEsMHcYC2Z3EmqCevb/pQ+XMlf6EfbbgP8sr4Z0xlPj/dvPK1GTSq6UzWMFIps7Zk845tbPK8oK28XsGi47kDMPb979Je0b5yCMPA87aCP44oxxHNwmXux/FhIngNprTa/VcPzov4RTmlo4/RUEYaq5ZfxQ6CM2MFgBa9IwdMH4GSoyttftqBqAAbHRAnTAoYQqiAe9lO932slmSgz3Pwd8Oi4D2x6hQ+2Q+vWujxFcLIGl4t2k3gX0z0+9GSGSnulgEmP1vHSJRmvuKAsnegxv8xfDI5NQP+tooWILUKQzGFstgiQt6IgS45I1Ylf7pA5xgITZ+88Y6Cn/VjOpbXzqYlfxwF5f3vbNIAA="
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 8629,
     "status": "ok",
     "timestamp": 1734596658932,
     "user": {
      "displayName": "yuzhen",
      "userId": "05774191734922144334"
     },
     "user_tz": -480
    },
    "id": "8XEjqFCagCdT",
    "outputId": "a6b218a5-2496-4670-b855-0ca1206442e2"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Succeed: Total num: 1, size: 443,392,171. OK num: 1(download 1 objects).\n",
      "\n",
      "average speed 52653000(byte/s)\n",
      "\n",
      "8.422159(s) elapsed\n"
     ]
    }
   ],
   "source": [
    "!ossutil cp oss://tianchi-race-prod-sh/file/race/documents/532220/valset.zip ./valset.zip -i STS.NTxjYRbJcSd3LMqwbLzx2RauB -k fx2cTZyHS84oQV2vwFPW53xMQCBk86FUYhxJrqFNF9m --endpoint=oss-cn-shanghai.aliyuncs.com --sts-token=CAISpwN1q6Ft5B2yfSjIr5fNIePmj5VC5KbYTmvAk2IZdvcevaTeoDz2IHhPfHlpAe0Zs/Q/nWpW6PYclrhvQKhJTFDNacJ62ckMq1n7O9IrQTJeO+ZW5qe+EE2/VjQOta27OpcGJbGwU/OpbE++2U0X6LDmdDKkckW4OJmS8/BOZcgWWQ/KClgjA8xNdCRvtOgQN3baKYygUHjQj3HXEVBjtydllGp78t7f+MCH7QfEh1CI6406ro/qcJ+/dJsubtUtT9a82ud2d+/b2SVdrgBQ86szl6wD9zbDs5aHClJcpBmBOPfR/9tzN0gkPfJgQfYDsvH4jvBk/P7Sj8bVs08RZLgFAnuHHdjxnpWZSL6TW4xnJeqhCRPkycuSM5T5iQQgbE8AORlCE9hbcScrUUx1EmyFd//3oQqUPFf9UdaZ0agw2pp0ilnh4dORKkTKXq2d1i8UKk70trWO3Ld8NwXDBUxmG2QkGzsPbz2V/5vp2SYV4CVk6bhYsoG0UpX7m7yfAb2f8+t0Yu6kJbF9svF+L99lyCBRbDmZBszo5A56G2INJbKEhveFUfcagAGPs3DxVy6kxPuJPXK324LDx6ZGdfUSdWqmlNQ3C1uCblKNxJOquFAizrtz8SOtLFow/endDCFgTqslGRiaPxSed1x32ANmabZnZlsNG22WJBTqDHpzrspu+TQkVO4+ATqHJdtdHNwJblL8uq/zSm/cfK/YTa+sPruDx7wOdnaXySAA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 34461,
     "status": "ok",
     "timestamp": 1734596700993,
     "user": {
      "displayName": "yuzhen",
      "userId": "05774191734922144334"
     },
     "user_tz": -480
    },
    "id": "n1PQ14_LgVdn",
    "outputId": "51e30615-b6d3-427b-8c8f-ea524ee5df55"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Succeed: Total num: 1, size: 2,849,495,917. OK num: 1(download 1 objects).\n",
      "\n",
      "average speed 82969000(byte/s)\n",
      "\n",
      "34.344821(s) elapsed\n"
     ]
    }
   ],
   "source": [
    "!ossutil cp oss://tianchi-race-prod-sh/file/race/documents/532220/trainset.zip ./trainset.zip -i STS.NTZcTzYxME3j8twJCTHX8zEN7 -k DqVvhuoWK4q65RwqMy8M9Nb5oCs2Zw7BRJC6bD9YPsT6 --endpoint=oss-cn-shanghai.aliyuncs.com --sts-token=CAISqQN1q6Ft5B2yfSjIr5fvKO7OtKds8vGBOlLGrkMBRNcUlYDl1Tz2IHhPfHlpAe0Zs/Q/nWpW6PYclrhvQKhJTFDNacJ62ckMq1n7O9JiSjNeO+ZW5qe+EE2/VjQMta27OpcIJbGwU/OpbE++2U0X6LDmdDKkckW4OJmS8/BOZcgWWQ/KClgjA8xNdCRvtOgQN3baKYyiUHjQj3HXEVBjtydllGp78t7f+MCH7QfEh1CI6Y00ro/qcJ+/dJsubtUtT9a82ud2d+/b2SVdrgBQ86szl6wD9zbDs5aHClJcpBmBOPfR/9tzN0gkPfJgQfYDsOL1lPtjt/CVhYXviTQ1ZL0MCnSOG9j5mJqaRr75a+xUL+irZy7/tfmULYTwvg8eZnYWCRhHYdJJKAUrUUd0GmiCd/D6qACTOFn9G/afrr032Jx+z1St8dOWLkOCX/CEySIfM5Msvovxwbj9dAYLG41xkGwkGzsPb979xtWm86yNfI3CCazDhIARL2DWzhwPXYminoo1R+tRMJwIL0RjKuponZVkYRoJKdaMznNwXggD5d5jbskuZ/fXgBqAAXlR6wcgjNkbixTkwtPcDzi0mi+jailf/0t0mGnUOIn6V3gLwCphoeh5ArTjORwV8QcDJUzzxnDauTVEe3X4DeCFQFq2GOnEU7wGVWru+dEONW3nRMKaDKD3GJRk96v1OzkIc5KSnbQeSh5GIV2iUAtRtV6+2XB9J8nLqonKzfMaIAA="
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "XuRiKBvRgaGr"
   },
   "outputs": [],
   "source": [
    "!unzip trainset.zip;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "o6VyzeWngctF"
   },
   "outputs": [],
   "source": [
    "!unzip annotations.zip; unzip valset.zip"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# !pip install yolov5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# import os\n",
    "# import torch\n",
    "# from torch.utils.data import Dataset\n",
    "# from PIL import Image\n",
    "# import pandas as pd\n",
    "\n",
    "# class CustomDataset(Dataset):\n",
    "#     def __init__(self, txt_file, img_dir, yolo_model, apply_yolo=False, transform=None, target_size=(224, 224)):\n",
    "#         self.data_frame = pd.read_csv(txt_file, sep='\\s+', header=None, names=['image_name', 'age_month'])\n",
    "#         self.data_frame = self.data_frame[(self.data_frame['age_month'] >= 0) & (self.data_frame['age_month'] < 192)]\n",
    "#         self.transform = transform\n",
    "#         self.image_dir = img_dir\n",
    "#         self.yolo_model = yolo_model\n",
    "#         self.target_size = target_size\n",
    "#         self.apply_yolo = apply_yolo\n",
    "\n",
    "#         self.all_predictions = {}\n",
    "\n",
    "#         if apply_yolo:\n",
    "#             for img_name in self.data_frame['image_name']:\n",
    "#                 img_path = os.path.join(self.image_dir, img_name)\n",
    "#                 img = Image.open(img_path)\n",
    "#                 results = self.yolo_model(img)\n",
    "#                 detections = results.pandas().xyxy[0]\n",
    "#                 dog_heads = detections[detections['name'] == 'dog']\n",
    "#                 self.all_predictions[img_name] = dog_heads\n",
    "\n",
    "#     def __len__(self):\n",
    "#         return len(self.data_frame)\n",
    "\n",
    "#     def __getitem__(self, idx):\n",
    "#         img_name = self.data_frame.iloc[idx, 0]\n",
    "#         img_path = os.path.join(self.image_dir, img_name)\n",
    "#         img = Image.open(img_path)\n",
    "\n",
    "#         if self.apply_yolo:\n",
    "#             predictions = self.all_predictions.get(img_name)\n",
    "\n",
    "#             if predictions is not None and not predictions.empty:\n",
    "#                 xmin, ymin, xmax, ymax = predictions.iloc[0][['xmin', 'ymin', 'xmax', 'ymax']]\n",
    "#                 cropped_img = img.crop((xmin, ymin, xmax, ymax))\n",
    "\n",
    "#                 if self.target_size:\n",
    "#                     cropped_img = cropped_img.resize(self.target_size)\n",
    "#         else:\n",
    "#             cropped_img = img\n",
    "\n",
    "#         age = float(self.data_frame.iloc[idx, 1])\n",
    "\n",
    "#         if self.transform:\n",
    "#             cropped_img = self.transform(cropped_img)\n",
    "\n",
    "#         return cropped_img, age\n",
    "\n",
    "\n",
    "# model = torch.hub.load('ultralytics/yolov5', 'yolov5s')\n",
    "# transform = transforms.Compose([\n",
    "#     transforms.ToTensor(),\n",
    "#     transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n",
    "# ])\n",
    "\n",
    "# train_dataset = CustomDataset('annotations/train.txt', './trainset/', model, apply_yolo=True, transform=transform, target_size=(224, 224))\n",
    "# test_dataset = CustomDataset('annotations/val.txt', './valset/', model, apply_yolo=False, transform=transform, target_size=(224, 224))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 464,
     "status": "ok",
     "timestamp": 1734599866960,
     "user": {
      "displayName": "yuzhen",
      "userId": "05774191734922144334"
     },
     "user_tz": -480
    },
    "id": "vJS7sgVBCHpT",
    "outputId": "e31d4adc-4614-40bd-d934-28eaf1558b0b"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.10/dist-packages/torch/utils/data/dataloader.py:617: UserWarning: This DataLoader will create 4 worker processes in total. Our suggested max number of worker in current system is 2, which is smaller than what this DataLoader is going to create. Please be aware that excessive worker creation might get DataLoader running slow or even freeze, lower the worker number to avoid potential slowness/freeze if necessary.\n",
      "  warnings.warn(\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.optim as optim\n",
    "from torchvision import transforms, datasets, models\n",
    "from torch.utils.data import DataLoader, Dataset\n",
    "import pandas as pd\n",
    "from PIL import Image\n",
    "import time\n",
    "from tqdm import tqdm\n",
    "\n",
    "\n",
    "# 自定义数据集类\n",
    "class CustomDataset(Dataset):\n",
    "    def __init__(self, txt_file, img_dir, transform=None):\n",
    "        self.data_frame = pd.read_csv(txt_file, sep='\\s+', header=None, names=['image_name', 'age_month'])\n",
    "        # 过滤标签超出范围的数据\n",
    "        self.data_frame = self.data_frame[(self.data_frame['age_month'] >= 0) & (self.data_frame['age_month'] < 192)]\n",
    "        self.transform = transform\n",
    "        self.image_dir = img_dir  \n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self.data_frame)\n",
    "\n",
    "    def __getitem__(self, idx):\n",
    "        img_name = os.path.join(self.image_dir, self.data_frame.iloc[idx, 0])\n",
    "        image = Image.open(img_name).convert('RGB')\n",
    "        age = float(self.data_frame.iloc[idx, 1])\n",
    "\n",
    "        if self.transform:\n",
    "            image = self.transform(image)\n",
    "\n",
    "        return image, age\n",
    "\n",
    "# 数据预处理和增强\n",
    "data_transforms = {\n",
    "    'train': transforms.Compose([\n",
    "        #transforms.Resize((224, 224)),\n",
    "        transforms.RandomResizedCrop(224),\n",
    "        transforms.RandomHorizontalFlip(),\n",
    "        #transforms.ColorJitter(brightness=0.94, contrast=0.94), # 添加噪声\n",
    "        transforms.ToTensor(),\n",
    "        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])  # ImageNet 标准化\n",
    "\n",
    "    ]),\n",
    "    'val': transforms.Compose([\n",
    "        transforms.Resize(256),\n",
    "        transforms.CenterCrop(224),\n",
    "        transforms.ToTensor(),\n",
    "        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])\n",
    "    ]),\n",
    "}\n",
    "\n",
    "# 加载数据集\n",
    "train_txt = 'annotations/train.txt'\n",
    "val_txt = 'annotations/val.txt'\n",
    "train_root = r'./trainset/'\n",
    "val_root = r'./valset/'\n",
    "\n",
    "train_dataset = CustomDataset(train_txt, train_root, transform=data_transforms['train'])\n",
    "val_dataset = CustomDataset(val_txt, val_root, transform=data_transforms['val'])\n",
    "\n",
    "train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=4, pin_memory=True)\n",
    "val_loader = DataLoader(val_dataset, batch_size=32, shuffle=False, num_workers=4, pin_memory=True)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 48097,
     "status": "ok",
     "timestamp": 1734602800186,
     "user": {
      "displayName": "yuzhen",
      "userId": "05774191734922144334"
     },
     "user_tz": -480
    },
    "id": "_S99nzZpCJ7d",
    "outputId": "93cf94a8-e2cf-4d62-ff8c-07c97b1084f5"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.10/dist-packages/torchvision/models/_utils.py:208: UserWarning: The parameter 'pretrained' is deprecated since 0.13 and may be removed in the future, please use 'weights' instead.\n",
      "  warnings.warn(\n",
      "/usr/local/lib/python3.10/dist-packages/torchvision/models/_utils.py:223: UserWarning: Arguments other than a weight enum or `None` for 'weights' are deprecated since 0.13 and may be removed in the future. The current behavior is equivalent to passing `weights=ResNet50_Weights.IMAGENET1K_V1`. You can also use `weights=ResNet50_Weights.DEFAULT` to get the most up-to-date weights.\n",
      "  warnings.warn(msg)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 0/9\n",
      "----------\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "train Loss: 28.0889: 100%|██████████| 623/623 [04:15<00:00,  2.44it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train Loss: 28.0889\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "val Loss: 24.3750: 100%|██████████| 94/94 [00:38<00:00,  2.46it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "val Loss: 24.3750\n",
      "Epoch Time: 293.74 秒\n",
      "Epoch 1/9\n",
      "----------\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "train Loss: 26.0945: 100%|██████████| 623/623 [04:15<00:00,  2.44it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train Loss: 26.0945\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "val Loss: 25.7770: 100%|██████████| 94/94 [00:33<00:00,  2.78it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "val Loss: 25.7770\n",
      "Epoch Time: 289.30 秒\n",
      "Epoch 2/9\n",
      "----------\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "train Loss: 24.9961: 100%|██████████| 623/623 [04:18<00:00,  2.41it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train Loss: 24.9961\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "val Loss: 24.6197: 100%|██████████| 94/94 [00:33<00:00,  2.78it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "val Loss: 24.6197\n",
      "Epoch Time: 292.99 秒\n",
      "Epoch 3/9\n",
      "----------\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "train Loss: 25.6400: 100%|██████████| 623/623 [04:19<00:00,  2.40it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train Loss: 25.6400\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "val Loss: 24.3440: 100%|██████████| 94/94 [00:32<00:00,  2.85it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "val Loss: 24.3440\n",
      "Epoch Time: 292.85 秒\n",
      "Epoch 4/9\n",
      "----------\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "train Loss: 24.0389: 100%|██████████| 623/623 [04:15<00:00,  2.44it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train Loss: 24.0389\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "val Loss: 25.7818: 100%|██████████| 94/94 [00:36<00:00,  2.57it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "val Loss: 25.7818\n",
      "Epoch Time: 292.34 秒\n",
      "Epoch 5/9\n",
      "----------\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "train Loss: 23.1029: 100%|██████████| 623/623 [04:14<00:00,  2.45it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train Loss: 23.1029\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "val Loss: 23.3188: 100%|██████████| 94/94 [00:39<00:00,  2.38it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "val Loss: 23.3188\n",
      "Epoch Time: 294.34 秒\n",
      "Epoch 6/9\n",
      "----------\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "train Loss: 22.1753: 100%|██████████| 623/623 [04:13<00:00,  2.46it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train Loss: 22.1753\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "val Loss: 23.3408: 100%|██████████| 94/94 [00:40<00:00,  2.32it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "val Loss: 23.3408\n",
      "Epoch Time: 294.75 秒\n",
      "Epoch 7/9\n",
      "----------\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "train Loss: 21.1196: 100%|██████████| 623/623 [04:11<00:00,  2.48it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train Loss: 21.1196\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "val Loss: 26.6544: 100%|██████████| 94/94 [00:41<00:00,  2.25it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "val Loss: 26.6544\n",
      "Epoch Time: 293.83 秒\n",
      "Epoch 8/9\n",
      "----------\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "train Loss: 20.3589: 100%|██████████| 623/623 [04:08<00:00,  2.50it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train Loss: 20.3589\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "val Loss: 24.1777: 100%|██████████| 94/94 [00:44<00:00,  2.11it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "val Loss: 24.1777\n",
      "Epoch Time: 293.72 秒\n",
      "Epoch 9/9\n",
      "----------\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "train Loss: 19.3100: 100%|██████████| 623/623 [04:07<00:00,  2.52it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train Loss: 19.3100\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "val Loss: 26.0869: 100%|██████████| 94/94 [00:41<00:00,  2.29it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "val Loss: 26.0869\n",
      "Epoch Time: 288.60 秒\n"
     ]
    }
   ],
   "source": [
    "# 加载预训练的 ResNet50 模型并修改最后的全连接层\n",
    "model = models.resnet50(pretrained=True)\n",
    "num_ftrs = model.fc.in_features\n",
    "model.fc = nn.Linear(num_ftrs, 1)  # 输出一个值，表示月龄\n",
    "\n",
    "# 将模型移动到 GPU（如果可用）\n",
    "device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n",
    "model = model.to(device)\n",
    "\n",
    "# 定义损失函数和优化器\n",
    "criterion = nn.L1Loss()  # 使用平均绝对误差（MAE）作为损失函数\n",
    "optimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)\n",
    "\n",
    "# 训练模型\n",
    "num_epochs = 10\n",
    "train_losses = []\n",
    "val_losses = []\n",
    "\n",
    "for epoch in range(num_epochs):\n",
    "    print(f'Epoch {epoch}/{num_epochs - 1}')\n",
    "    print('-' * 10)\n",
    "    start_time = time.time()\n",
    "\n",
    "    # 每个 epoch 都有训练和验证阶段\n",
    "    for phase in ['train', 'val']:\n",
    "        if phase == 'train':\n",
    "            model.train()  # 设置模型为训练模式\n",
    "            data_loader = train_loader\n",
    "        else:\n",
    "            model.eval()   # 设置模型为评估模式\n",
    "            data_loader = val_loader\n",
    "\n",
    "        running_loss = 0.0\n",
    "        running_corrects = 0.0\n",
    "\n",
    "        data_iter = tqdm(enumerate(data_loader), total=len(data_loader), desc=f'{phase} 阶段')\n",
    "\n",
    "        for idx, (inputs, labels) in data_iter:\n",
    "            inputs = inputs.to(device)\n",
    "            labels = labels.to(device).unsqueeze(1)\n",
    "\n",
    "            with torch.set_grad_enabled(phase == 'train'):\n",
    "                outputs = model(inputs)\n",
    "                loss = criterion(outputs, labels)\n",
    "\n",
    "                if phase == 'train':\n",
    "                    optimizer.zero_grad()\n",
    "                    loss.backward()\n",
    "                    optimizer.step()\n",
    "\n",
    "            running_loss += loss.item() * inputs.size(0)\n",
    "            epoch_loss = running_loss / len(data_loader.dataset)\n",
    "\n",
    "            # 更新 tqdm 进度条的描述\n",
    "            data_iter.set_description(f'{phase} Loss: {epoch_loss:.4f}')\n",
    "        if(phase == 'train'):\n",
    "            train_losses.append(epoch_loss)\n",
    "        else:\n",
    "            val_losses.append(epoch_loss)\n",
    "        print(f'{phase} Loss: {epoch_loss:.4f}')\n",
    "    end_time = time.time()\n",
    "    epoch_time = end_time - start_time\n",
    "    print(f\"Epoch Time: {epoch_time:.2f} 秒\")\n",
    "\n",
    "\n",
    "# 保存模型（可选）\n",
    "torch.save(model.state_dict(), 'resnet50_pet_age.pth')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 472
    },
    "executionInfo": {
     "elapsed": 1212,
     "status": "ok",
     "timestamp": 1734602820590,
     "user": {
      "displayName": "yuzhen",
      "userId": "05774191734922144334"
     },
     "user_tz": -480
    },
    "id": "8S28VseUNEDK",
    "outputId": "bd2ad951-1de5-4f52-e24f-2486d29b4891"
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjIAAAHHCAYAAACle7JuAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAAB6wklEQVR4nO3dd3gUVRvG4d+mF1IIEEIJvffeAgiKFOlFFJCiICoJyqdYUFGxIYqKAoJYQASkKUWq9I50CL1Ik14TSEjd/f6YEIyAhJBkdpPnvq69mOzOzryRyD6Zec85FpvNZkNERETEATmZXYCIiIhIWinIiIiIiMNSkBERERGHpSAjIiIiDktBRkRERByWgoyIiIg4LAUZERERcVgKMiIiIuKwFGRERETEYSnIiIiIiMNSkBERACZMmIDFYrnrY+PGjWaX+J9WrlxJhw4dCAoKws3NjcDAQFq3bs1vv/1mdmkikoFczC5AROzL+++/T9GiRW97vkSJEiZUkzrvvvsu77//PiVLluS5556jcOHCXLp0iQULFtCxY0cmT55M165dzS5TRDKAgoyIpNCiRQtq1KhxX+9JSEjAarXi5uZ222tRUVF4e3unuR6bzUZMTAyenp53fH3mzJm8//77dOrUiSlTpuDq6pr82quvvsrixYuJj49P8/n/KTo6Gi8vr3Q5loikD91aEpH7cuzYMSwWC8OHD2fEiBEUL14cd3d39u7dy3vvvYfFYmHv3r107dqVnDlzUr9+fcAIOx988EHy/kWKFOHNN98kNjY2xfGLFClCq1atWLx4MTVq1MDT05Nvv/32rvUMHjyYgIAAfvzxxxQh5qZmzZrRqlUr4Nbts2PHjqXYZ+XKlVgsFlauXJn8XKNGjahQoQJbt26lYcOGeHl58eabb9KqVSuKFSt2x1rq1q17WwicNGkS1atXx9PTk4CAAJ588klOnjx51+9HRO6PrsiISAoRERFcvHgxxXMWi4VcuXKleG78+PHExMTQt29f3N3dCQgISH7t8ccfp2TJknz88cfYbDYA+vTpw08//USnTp145ZVX+PPPPxk6dCj79u1j1qxZKY594MABunTpwnPPPcezzz5L6dKl71jroUOH2L9/P8888ww+Pj7p8e2ncOnSJVq0aMGTTz7JU089Rd68ealevTo9evRg8+bN1KxZM3nf48ePs3HjRj777LPk5z766CMGDx5M586d6dOnDxcuXGDkyJE0bNiQ7du34+/vn+41i2Q3CjIikkKTJk1ue87d3Z2YmJgUz/39998cPnyYPHny3LZ/5cqVmTJlSvLXO3fu5KeffqJPnz589913APTr14/AwECGDx/OihUraNy4cfL+hw8fZtGiRTRr1uw/a923bx8AFStWTP03eB/Onj3L2LFjee6555Kfi4yMxN3dnWnTpqUIMtOnT8disdC5c2fACDbvvvsuH374IW+++Wbyfh06dKBq1ap88803KZ4XkbTRrSURSWH06NEsWbIkxWPhwoW37dexY8c7hhiA559/PsXXCxYsAODll19O8fwrr7wCwPz581M8X7Ro0XuGGDBCBZAhV2PACHBPP/10iud8fX1p0aIF06dPT77aBDBt2jTq1KlDoUKFAPjtt9+wWq107tyZixcvJj+CgoIoWbIkK1asyJCaRbIbXZERkRRq1aqVqmbfO41suttrx48fx8nJ6baRT0FBQfj7+3P8+PFUH/uffH19Abh27Vqq9r9fBQoUuGMD8xNPPMHs2bPZsGED9erV48iRI2zdupURI0Yk73Po0CFsNhslS5a847Hv1M8jIvdPQUZE0uRuo4j+6zWLxfLAx/6nMmXKABAeHp6q/e92/sTExPuqo3Xr1nh5eTF9+nTq1avH9OnTcXJy4vHHH0/ex2q1YrFYWLhwIc7OzrcdI0eOHKmqWUT+m4KMiGS4woULY7VaOXToEGXLlk1+/ty5c1y9epXChQun6bilSpWidOnSzJkzh6+++uqe4SBnzpwAXL16NcXz/74idC/e3t60atWKGTNm8MUXXzBt2jQaNGhA/vz5k/cpXrw4NpuNokWLUqpUqfs6voiknnpkRCTDPfbYYwApbr0AfPHFFwC0bNkyzcceMmQIly5dok+fPiQkJNz2+h9//MG8efMAI1wArF69Ovn1xMRExo0bd9/nfeKJJzh9+jTff/89O3fu5IknnkjxeocOHXB2dmbIkCEpemnAmBvn0qVL931OEbmdrsiISAoLFy5k//79tz1fr169u86fci+VK1emZ8+ejBs3jqtXr/LQQw+xadMmfvrpJ9q1a5dixNL9euKJJwgPD+ejjz5i+/btdOnSJXlm30WLFrFs2bLkEVTly5enTp06DBo0iMuXLxMQEMDUqVPvGIDu5bHHHsPHx4eBAwfi7OxMx44dU7xevHhxPvzwQwYNGsSxY8do164dPj4+HD16lFmzZtG3b18GDhyY5u9bRAwKMiKSwjvvvHPH58ePH5/mIAPw/fffU6xYMSZMmMCsWbMICgpi0KBBvPvuu2k+5k0ffvghDz/8MF9//TVjxozh8uXL5MyZkzp16jBnzhzatGmTvO/kyZN57rnn+OSTT/D396d37940btyYRx999L7O6eHhQZs2bZg8eTJNmjQhMDDwtn3eeOMNSpUqxZdffsmQIUMACA4OpmnTpilqEpG0s9j+fc1TRERExEGoR0ZEREQcloKMiIiIOCwFGREREXFYCjIiIiLisBRkRERExGEpyIiIiIjDyvLzyFitVk6fPo2Pj0+q13kRERERc9lsNq5du0b+/Plxcrr7dZcsH2ROnz5NcHCw2WWIiIhIGpw8eZKCBQve9fUsH2R8fHwA4z+Er6+vydWIiIhIakRGRhIcHJz8OX43WT7I3Lyd5OvrqyAjIiLiYO7VFqJmXxEREXFYCjIiIiLisBRkRERExGFl+R4ZERF5MImJicTHx5tdhmQxrq6uODs7P/BxFGREROSObDYbZ8+e5erVq2aXIlmUv78/QUFBDzTPm4KMiIjc0c0QExgYiJeXlyYVlXRjs9mIjo7m/PnzAOTLly/Nx1KQERGR2yQmJiaHmFy5cpldjmRBnp6eAJw/f57AwMA032ZSs6+IiNzmZk+Ml5eXyZVIVnbz5+tBerAUZERE5K50O0kyUnr8fCnIiIiIiMNSkBEREbmHIkWKMGLEiFTvv3LlSiwWi0Z8ZQIFGRERyTIsFst/Pt577700HXfz5s307ds31fvXq1ePM2fO4Ofnl6bzpZYCk0YtpZnNZmPFgfM0KhWIk5PuIYuI2IMzZ84kb0+bNo133nmHAwcOJD+XI0eO5G2bzUZiYiIuLvf+KMyTJ8991eHm5kZQUNB9vUfSxtQrMkOHDqVmzZr4+PgQGBhIu3btUvzAgTGPQffu3QkKCsLb25tq1arx66+/mlTxLf1/2c4zE7Yw+c/jZpciIiJJgoKCkh9+fn5YLJbkr/fv34+Pjw8LFy6kevXquLu7s3btWo4cOULbtm3JmzcvOXLkoGbNmixdujTFcf99a8lisfD999/Tvn17vLy8KFmyJHPnzk1+/d9XSiZMmIC/vz+LFy+mbNmy5MiRg+bNm6cIXgkJCbz44ov4+/uTK1cuXn/9dXr27Em7du3S/N/jypUr9OjRg5w5c+Ll5UWLFi04dOhQ8uvHjx+ndevW5MyZE29vb8qXL8+CBQuS39utWzfy5MmDp6cnJUuWZPz48WmuJaOYGmRWrVpFaGgoGzduZMmSJcTHx9O0aVOioqKS9+nRowcHDhxg7ty5hIeH06FDBzp37sz27dtNrBxqFgkAYOjC/Zy8HG1qLSIimcFmsxEdl2DKw2azpdv38cYbb/DJJ5+wb98+KlWqxPXr13nsscdYtmwZ27dvp3nz5rRu3ZoTJ07853GGDBlC586d2bVrF4899hjdunXj8uXLd90/Ojqa4cOH8/PPP7N69WpOnDjBwIEDk18fNmwYkydPZvz48axbt47IyEhmz579QN9rr1692LJlC3PnzmXDhg3YbDYee+yx5OHOoaGhxMbGsnr1asLDwxk2bFjyVavBgwezd+9eFi5cyL59+xgzZgy5c+d+oHoygqm3lhYtWpTi6wkTJhAYGMjWrVtp2LAhAOvXr2fMmDHUqlULgLfffpsvv/ySrVu3UrVq1Uyv+abudQozb9dpNh+7wpuzwpn4TC0NUxSRLO1GfCLl3llsyrn3vt8ML7f0+ch6//33efTRR5O/DggIoHLlyslff/DBB8yaNYu5c+cSFhZ21+P06tWLLl26APDxxx/z9ddfs2nTJpo3b37H/ePj4xk7dizFixcHICwsjPfffz/59ZEjRzJo0CDat28PwKhRo5KvjqTFoUOHmDt3LuvWraNevXoATJ48meDgYGbPns3jjz/OiRMn6NixIxUrVgSgWLFiye8/ceIEVatWpUaNGoBxVcoe2VWzb0REBGD8UN1Ur149pk2bxuXLl7FarUydOpWYmBgaNWp0x2PExsYSGRmZ4pERnJwsDOtYCXcXJ9YcusiMLX9nyHlERCR93fxgvun69esMHDiQsmXL4u/vT44cOdi3b989r8hUqlQpedvb2xtfX9/kKffvxMvLKznEgDEt/839IyIiOHfuXPIv7QDOzs5Ur179vr63f9q3bx8uLi7Url07+blcuXJRunRp9u3bB8CLL77Ihx9+SEhICO+++y67du1K3veFF15g6tSpVKlShddee43169enuZaMZDfNvlarlQEDBhASEkKFChWSn58+fTpPPPEEuXLlwsXFBS8vL2bNmkWJEiXueJyhQ4cyZMiQTKm5WJ4cvNK0FB8v2M8H8/fSsFQegvw8MuXcIiKZzdPVmb3vNzPt3OnF29s7xdcDBw5kyZIlDB8+nBIlSuDp6UmnTp2Ii4v7z+O4urqm+NpisWC1Wu9r//S8ZZYWffr0oVmzZsyfP58//viDoUOH8vnnn9O/f39atGjB8ePHWbBgAUuWLOGRRx4hNDSU4cOHm1rzv9nNFZnQ0FB2797N1KlTUzw/ePBgrl69ytKlS9myZQsvv/wynTt3Jjw8/I7HGTRoEBEREcmPkydPZmjdvesXo3KwP9diEnhrVrjpP5QiIhnFYrHg5eZiyiMjb92vW7eOXr160b59eypWrEhQUBDHjh3LsPPdiZ+fH3nz5mXz5s3JzyUmJrJt27Y0H7Ns2bIkJCTw559/Jj936dIlDhw4QLly5ZKfCw4O5vnnn+e3337jlVde4bvvvkt+LU+ePPTs2ZNJkyYxYsQIxo0bl+Z6MopdXJEJCwtj3rx5rF69moIFCyY/f+TIEUaNGsXu3bspX748AJUrV2bNmjWMHj2asWPH3nYsd3d33N3dM612ZycLn3WqRMuv17Bs/3nm7jxN2yoFMu38IiLyYEqWLMlvv/1G69atsVgsDB48+D+vrGSU/v37M3ToUEqUKEGZMmUYOXIkV65cSVWICw8Px8fHJ/lri8VC5cqVadu2Lc8++yzffvstPj4+vPHGGxQoUIC2bdsCMGDAAFq0aEGpUqW4cuUKK1asoGzZsgC88847VK9enfLlyxMbG8u8efOSX7MnpgYZm81G//79mTVrFitXrqRo0aIpXo+ONkYDOTmlvHDk7Oxsyg/Z3ZTK68OLD5fk8yUHeXfuHuoVz00en8wLUyIiknZffPEFzzzzDPXq1SN37ty8/vrrGdZf+V9ef/11zp49S48ePXB2dqZv3740a9YsVatC3xwgc5OzszMJCQmMHz+el156iVatWhEXF0fDhg1ZsGBB8m2uxMREQkND+fvvv/H19aV58+Z8+eWXgDEXzqBBgzh27Bienp40aNDgtrsm9sBiM/FeSL9+/ZgyZQpz5syhdOnSyc/7+fnh6elJfHw85cqVI1++fAwfPpxcuXIxe/ZsXn31VebNm8djjz12z3NERkbi5+dHREQEvr6+Gfa9xCdaaTtqHXvPRNKyYj5Gd6uWYecSEcloMTExHD16lKJFi+Lhod4/M1itVsqWLUvnzp354IMPzC4nQ/zXz1lqP79N7ZEZM2YMERERNGrUiHz58iU/pk2bBhiNUQsWLCBPnjy0bt2aSpUqMXHiRH766adUhZjM5OrsxKedKuHsZGF++BkWhp+595tERESSHD9+nO+++46DBw8SHh7OCy+8wNGjR+natavZpdk1028t3UvJkiXtYibf1KhQwI8XHirOqBWHGTxnD3WK5SKnt5vZZYmIiANwcnJiwoQJDBw4EJvNRoUKFVi6dKld9qXYE7to9s1K+j9SgkV7znL4/HU+mLeXL56oYnZJIiLiAIKDg1m3bp3ZZTgcuxl+nVW4uzjzWadKOFngt+2nWL7/nNkliYiIZFkKMhmgaqGc9GlgTPP85m+7iYyJN7kiERGRrElBJoO8/Ggpiub25mxkDEMX7DO7HBERkSxJQSaDeLg6M6yjsQ7HL5tOsvbQRZMrEhERyXoUZDJQraIB9KxbGIA3fttFVGyCyRWJiIhkLQoyGey15mUo4O/J31du8NniA2aXIyIikqUoyGQwb3eX5FtME9YfY9PRyyZXJCIi99KoUSMGDBiQ/HWRIkUYMWLEf77HYrEwe/bsBz53eh0nu1CQyQT1S+bmyZrBALz+6y5i4hNNrkhEJGtq3bo1zZs3v+Nra9aswWKxsGvXrvs+7ubNm+nbt++DlpfCe++9R5UqVW57/syZM7Ro0SJdz/VvEyZMwN/fP0PPkVkUZDLJmy3LEuTrwdGLUXy55KDZ5YiIZEm9e/dmyZIl/P3337e9Nn78eGrUqEGlSpXu+7h58uTBy8srPUq8p6CgINzdtfBwainIZBJfD1c+al8BgO/W/MX2E1dMrkhEJOtp1aoVefLkYcKECSmev379OjNmzKB3795cunSJLl26UKBAAby8vKhYsSK//PLLfx7337eWDh06RMOGDfHw8KBcuXIsWbLktve8/vrrlCpVCi8vL4oVK8bgwYOJjzfmFZswYQJDhgxh586dWCwWLBZLcs3/vrUUHh7Oww8/jKenJ7ly5aJv375cv349+fVevXrRrl07hg8fTr58+ciVKxehoaHJ50qLEydO0LZtW3LkyIGvry+dO3fm3LlbE7zu3LmTxo0b4+Pjg6+vL9WrV2fLli2AsWZU69atyZkzJ97e3pQvX54FCxakuZZ70RIFmeiRsnlpX7UAs7af4rWZu5j3Yn3cXe69PLuIiF2w2SA+2pxzu3qBxXLP3VxcXOjRowcTJkzgrbfewpL0nhkzZpCYmEiXLl24fv061atX5/XXX8fX15f58+fTvXt3ihcvTq1ate55DqvVSocOHcibNy9//vknERERKfppbvLx8WHChAnkz5+f8PBwnn32WXx8fHjttdd44okn2L17N4sWLWLp0qUA+Pn53XaMqKgomjVrRt26ddm8eTPnz5+nT58+hIWFpQhrK1asIF++fKxYsYLDhw/zxBNPUKVKFZ599tl7fj93+v5uhphVq1aRkJBAaGgoTzzxBCtXrgSgW7duVK1alTFjxuDs7MyOHTtwdXUFIDQ0lLi4OFavXo23tzd79+4lR44c911HainIZLJ3WpVjzaELHDp/nVHLD/NK09JmlyQikjrx0fBxfnPO/eZpcPNO1a7PPPMMn332GatWraJRo0aAcVupY8eO+Pn54efnx8CBA5P379+/P4sXL2b69OmpCjJLly5l//79LF68mPz5jf8eH3/88W19LW+//XbydpEiRRg4cCBTp07ltddew9PTkxw5cuDi4kJQUNBdzzVlyhRiYmKYOHEi3t7G9z9q1Chat27NsGHDyJs3LwA5c+Zk1KhRODs7U6ZMGVq2bMmyZcvSFGSWLVtGeHg4R48eJTjY6O+cOHEi5cuXZ/PmzdSsWZMTJ07w6quvUqZMGcBY4PmmEydO0LFjRypWrAhAsWLF7ruG+6FbS5ksp7cbH7Q1bjF9s/IIu09FmFyRiEjWUqZMGerVq8ePP/4IwOHDh1mzZg29e/cGIDExkQ8++ICKFSsSEBBAjhw5WLx4MSdOnEjV8fft20dwcHByiAGoW7fubftNmzaNkJAQgoKCyJEjB2+//Xaqz/HPc1WuXDk5xACEhIRgtVo5cODWlB7ly5fH2fnWFf58+fJx/vz5+zrXP88ZHBycHGIAypUrh7+/P/v2GTPVv/zyy/Tp04cmTZrwySefcOTIkeR9X3zxRT788ENCQkJ4991309RcfT90RcYELSrm47GKQSwIP8trM3cxJywEV2dlShGxc65expURs859H3r37k3//v0ZPXo048ePp3jx4jz00EMAfPbZZ3z11VeMGDGCihUr4u3tzYABA4iLi0u3cjds2EC3bt0YMmQIzZo1w8/Pj6lTp/L555+n2zn+6eZtnZssFgtWqzVDzgXGiKuuXbsyf/58Fi5cyLvvvsvUqVNp3749ffr0oVmzZsyfP58//viDoUOH8vnnn9O/f/8MqUWfniYZ0qYC/l6u7D0Tyberjtz7DSIiZrNYjNs7ZjxS0R/zT507d8bJyYkpU6YwceJEnnnmmeR+mXXr1tG2bVueeuopKleuTLFixTh4MPWjScuWLcvJkyc5c+ZM8nMbN25Msc/69espXLgwb731FjVq1KBkyZIcP348xT5ubm4kJv73dBxly5Zl586dREVFJT+3bt06nJycKF06Y1oTbn5/J0+eTH5u7969XL16lXLlyiU/V6pUKf73v//xxx9/0KFDB8aPH5/8WnBwMM8//zy//fYbr7zyCt99912G1AoKMqbJ4+POe63LA/D1ssMcPHfN5IpERLKOHDly8MQTTzBo0CDOnDlDr169kl8rWbIkS5YsYf369ezbt4/nnnsuxYice2nSpAmlSpWiZ8+e7Ny5kzVr1vDWW2+l2KdkyZKcOHGCqVOncuTIEb7++mtmzZqVYp8iRYpw9OhRduzYwcWLF4mNjb3tXN26dcPDw4OePXuye/duVqxYQf/+/enevXtyf0xaJSYmsmPHjhSPffv20aRJEypWrEi3bt3Ytm0bmzZtokePHjz00EPUqFGDGzduEBYWxsqVKzl+/Djr1q1j8+bNlC1bFoABAwawePFijh49yrZt21ixYkXyaxlBQcZEbavk55EygcQlWnl15i4SrTazSxIRyTJ69+7NlStXaNasWYp+lrfffptq1arRrFkzGjVqRFBQEO3atUv1cZ2cnJg1axY3btygVq1a9OnTh48++ijFPm3atOF///sfYWFhVKlShfXr1zN48OAU+3Ts2JHmzZvTuHFj8uTJc8ch4F5eXixevJjLly9Ts2ZNOnXqxCOPPMKoUaPu7z/GHVy/fp2qVaumeLRu3RqLxcKcOXPImTMnDRs2pEmTJhQrVoxp06YB4OzszKVLl+jRowelSpWic+fOtGjRgiFDhgBGQAoNDaVs2bI0b96cUqVK8c033zxwvXdjsdlsWfrTMzIyEj8/PyIiIvD19TW7nNucjYjh0S9WcS02gbceK8uzDTO2u1tEJDViYmI4evQoRYsWxcPDw+xyJIv6r5+z1H5+64qMyYL8PHi7lXHJbfgfBzh6Meoe7xAREZGbFGTsQOcawdQvkZvYBCuvz9yFVbeYREREUkVBxg5YLBaGdqiIl5szm45dZtKfx+/9JhEREVGQsRfBAV680cKYIfGThfs5edmkacBFREQciIKMHXmqdmFqFQkgOi6RQb+Fk8X7sEXEAejfIclI6fHzpSBjR5ycLAzrVAl3FyfWHr7I9C0n7/0mEZEMcHOm2OhoXR2WjHPz5+vfMxPfDy1RYGeK5vZmYNPSfLRgHx/O28dDpQIJ8tPQRxHJXM7Ozvj7+yev1+Pl5ZU8M67Ig7LZbERHR3P+/Hn8/f1TrBN1vxRk7NAz9YsyL/wMO09e5a1Z4Xzfs4b+ARGRTHdzVea0Lj4oci/+/v7/ufp3aijI2CFnJwufdapEq6/Xsmz/eebsOE27qgXMLktEshmLxUK+fPkIDAwkPj7e7HIki3F1dX2gKzE3KcjYqVJ5fXjxkRIM/+Mg7/2+h5ASucnj4252WSKSDTk7O6fLB45IRlCzrx177qHilMvny9XoeN6du9vsckREROyOgowdc3V24rPHK+HiZGFB+FkWhJ+595tERESyEQUZO1c+vx8vNCoOwDtzdnMlKs7kikREROyHgowDCHu4BCUDc3Dxehzvz9trdjkiIiJ2Q0HGAbi7OPNpp0o4WWDW9lMs23fO7JJERETsgoKMg6haKCd9GhQD4M1Z4UTc0FBIERERBRkH8vKjpSia25tzkbEMXbDP7HJERERMpyDjQDxcnRnWsRIWC0zdfJI1hy6YXZKIiIipFGQcTK2iAfSsWwSAN34NJyo2wdyCRERETKQg44BebVaagjk9OXX1Bp8u2m92OSIiIqZRkHFA3u4uDOtYCYCfNhxn09HLJlckIiJiDgUZBxVSIjddagUD8NrMndyISzS5IhERkcynIOPABj1WliBfD45diuaLJQfMLkdERCTTKcg4MF8PVz7uUAGAH9YeZduJKyZXJCIikrkUZBzcw2Xy0qFqAaw2eG3mLmITdItJRLKwuCi4ft7sKsSOKMhkAe+0LkfuHO4cPn+dkcsOm12OiEjGsNngpzbwVWU4p3XnxKAgkwX4e7nxYbvyAIxZdYTdpyJMrkhEJAOc2AintkB8NCz/wOxqxE4oyGQRzSvko2XFfCRabbw6cxfxiVazSxIRSV/bfrq1fWABnNxkXi1iNxRkspD32pQnp5cr+85EMnblEbPLERFJPzeuwp7ZxnaB6safS4cYt5skW1OQyULy+LjzXhvjFtPXyw9x8Nw1kysSEUkn4TMg4QYEloPHfwJnNzi+Fo4sM7syMZmCTBbTpnJ+mpQNJD7RxqszdpKgW0wi4uhsNtiadFupWk/wD4aazxpfL3sfrPp3LjtTkMliLBYLH7ariI+HCzv/juDHdUfNLklE5MGc3gbnwsHZHSp1Np5r8DK45YAzO2HfHHPrE1MpyGRBQX4eDG5ZDoDP/zjIXxeum1yRiMgDuHk1plxb8Aowtr1zQ90wY3v5h5CYYE5tYjoFmSzq8RoFaVAyN7EJVl7/dRdWqxriRMQBxV6D8JnGdvWeKV+rGwpeueDSYdgxOfNrE7ugIJNFWSwWhnaoiLebM5uPXeHnjcfNLklE5P7t/hXioyBXCSgckvI1D19o8IqxvWoYxMdkfn1iOgWZLKxgTi/eaFEGgGGL9nPycrTJFYmI3Kd/NvlaLLe/XqM3+BaEyFOw+fvMrU3sgoJMFtetdmFqFQ0gOi6RN37bhU1zLoiIozgbbjT6OrlCla533sfVAxq9bmyv+RxiIjOvPrELCjJZnJOThU87VsLD1Yl1hy8xbfNJs0sSEUmdm1djyrQ0mnvvpnJXyFUSblyGDaMypzaxGwoy2UCR3N4MbFoagI/m7+NMxA2TKxIRuYe4aNg13dj+d5Pvvzm7wMNvG9sbRsP1Cxlbm9gVBZls4umQolQJ9udabAJv/hauW0wiYt/2zoHYCPAvDEUb3Xv/cm0hXxWIu27cYpJsQ0Emm3B2svBZp0q4OTux4sAFZu84ZXZJIiJ3t3WC8We17uCUio8qiwWavGtsb/kBrp7IsNLEvijIZCMl8/rwUpOSALw3dy/nr2mooojYofP74eRGsDhDladS/75ijaFIA0iMg5XDMq4+sSsKMtlM34bFKJ/fl4gb8bw7Z4/Z5YiI3G7bROPPUs3BN1/q32exwCNJV2V2TjECkWR5CjLZjKuzE592qoSLk4WFu8+yIPyM2SWJiNySEAs7fzG279XkeyfBNaFMK7BZYcWH6Vub2CUFmWyofH4/+jUqDsA7c3ZzOSrO5IpERJLs+90YRu1bAEo0SdsxHn4bsBjHOrU1XcsT+6Mgk02FPlyCUnlzcPF6HO//rltMImIntiXNHVP1KXByTtsxAstC5SeN7WXvp09dYrcUZLIpdxdnPu1UGScLzN5xmtnbNYpJREx2+S84uhqwGEHmQTQaZMwI/NdK4yEZ4++tMCcUYiJMK8HUIDN06FBq1qyJj48PgYGBtGvXjgMHDty234YNG3j44Yfx9vbG19eXhg0bcuOGJnV7UFWC/Xm2YTEABkzbwTcrD2t+GRExz80m3xKPgH+hBztWzsJQ4xlje9n7oH/b0l/8DZj1HGyfBMs/Mq0MU4PMqlWrCA0NZePGjSxZsoT4+HiaNm1KVFRU8j4bNmygefPmNG3alE2bNrF582bCwsJwSs28AnJPrzYtTY+6hQH4dNEBXpmxk9iERJOrEpFsJzEetk82tqulocn3ThoOBFdvo09m/7z0OabcsnQIXDoEOYKg0RumlWGx2dGv4BcuXCAwMJBVq1bRsGFDAOrUqcOjjz7KBx98kKZjRkZG4ufnR0REBL6+vulZbpYyccMxhvy+l0SrjRqFc/Jt9+rkyuFudlkikl3snQvTu4N3ILy8F5xd0+e4yz6ANcMhd2notyHtfTeS0l+rYGIbY7vbTCj5aLqfIrWf33Z1WSMiwrjHFhAQAMD58+f5888/CQwMpF69euTNm5eHHnqItWvX3vUYsbGxREZGpnjIvfWoW4TxvWri4+HCluNXaDt6HQfOXjO7LBHJLpKbfLulX4gBCHkRPHPCxQOwc2r6HTc7i4kw+mIAqj+dISHmfthNkLFarQwYMICQkBAqVKgAwF9//QXAe++9x7PPPsuiRYuoVq0ajzzyCIcOHbrjcYYOHYqfn1/yIzg4ONO+B0fXsFQeZvWrR+FcXvx95QYdx6xnxf7zZpclIlnd1RNweJmxXa1H+h7bww/q/8/YXjnUmKdGHsyiQRBxEnIWgabmz9VjN0EmNDSU3bt3M3XqrcRstVoBeO6553j66aepWrUqX375JaVLl+bHH3+843EGDRpERERE8uPkyZOZUn9WUSLQh9n9QqhVNIDrsQn0/mkzP6w9qiZgEck42ycBNijaEAKKpf/xa/UFn3zGh++WO392SCrtnw87JgMWaDcW3HOYXZF9BJmwsDDmzZvHihUrKFiwYPLz+fIZU1OXK1cuxf5ly5blxIk7Lwjm7u6Or69viofcn5zebkzqXZvONQpitcEH8/by5qzdxCdazS5NRLIaa2JSkCH9mnz/zdUTHnrd2F49HGJ12zxNoi7C7y8Z2/X6Q+G65taTxNQgY7PZCAsLY9asWSxfvpyiRYumeL1IkSLkz5//tiHZBw8epHDhwplZarbj5uLEsI6VePOxMlgs8MumE/T8cRNXozULsIiko8NLIfIUeAZA2dYZd56qTxlXe6IvwsYxGXeerMpmM0JM1AUILAeN3zK7omSmBpnQ0FAmTZrElClT8PHx4ezZs5w9ezZ5jhiLxcKrr77K119/zcyZMzl8+DCDBw9m//799O7d28zSswWLxULfhsX5rnsNvN2cWX/kEu2/Wc9fF66bXZqIZBVbJxh/Vu4CLhk4UtLZ9daH7/qREHUp486VFe2aZgxhd3KB9mPB1cPsipKZOvzaYrHc8fnx48fTq1ev5K8/+eQTRo8ezeXLl6lcuTKffvop9evXT9U5NPw6few7E0mfn7Zw6uoN/DxdGdOtGvVK5Da7LBFxZJFn4MvyYEuE0E2Qp3TGns9qhXEN4Ww41A2DZuZN4uZQIv6Gb+pCbKSxjlXDVzPltKn9/LareWQygoJM+rlwLZa+P29h+4mruDhZeL9tBbrWfsDZN0Uk+1r9GSz/EArVhWcWZc45Dy2ByZ3A2R1e3A5+BTLnvI7KaoWf28HRVVCgBjyzGJxdMuXUDjmPjJjg6glY8i6c3X3PXfP4uPPLs3VoWyU/CVYbb84KZ8jve0i0ZuksLGkRfRmmdYc1n5tdidgrqxW2/WxsZ1ST752UaAKF6kFiLKwalnnndVSbvzdCjIuncUspk0LM/VCQyc4iz8CEVrBuBPzYzGi6uwcPV2dGPFGFVx4tBcD4dcfo/dNmrsXEZ3Cx4jDiomHKE7BvrrHGzZldZlck9ujoSrh6HNz9oFzbzDuvxQJN3jW2t0+Ci4cz79yO5uJhWPKOsf3oEMhd0tx67kJBJruKvgw/tzf+IXFygbjrMLnzrbVO/oPFYqH/IyUZ3bUaHq5OrDxwgY5j1nPycnQmFC52LTEeZvSEvzfdem7Z++bVI/Zra9JMvpU6g5tX5p67UB0o1dzozVlh/oRudikxwVgQMuEGFH0Iaj5rdkV3pSCTHcVeM+4RX9hnTBLV70+o2Nn4n3pOP1j1aapWim1ZKR/Tn6tLoI87B89dp+3odWw5djkTvgGxS1YrzO0Ph/4wLkO3G2uE5MNL4NjdlxWRbOj6BWNiNYDqmXhb6Z8eHgxYYM8sOL3DnBrs2boRcGoLuPtCu2/Ajhdqtt/KJGPEx8DUrsZqsJ4B0H025C4BHcbdmsZ7xUfGfAGJCfc8XKWC/swJC6F8fl8uR8XR9bs/+XXr3xn7PYh9WvoO7PwFLM7Q+Seo0uXWdPNLh6QqHEs2sXMKWOMhfzUIqmhODUEVoGInY3t52hYlzrLO7IKVnxjbLT4Fv4L/vb/JFGSyk8QE+LU3HF0NbjngqZkQWMZ4zWKBJu/BY8PB4mQs4Da1C8Tee86YfH6ezHi+Ls3LBxGXaOWVGTsZtmg/VjUB37e4BCvL95/jXGSM2aXcn3VfG3NzALQdBaWaGdsNXzOuzvy9CQ4sNK8+sR82G2ybaGybdTXmpsZvJl01XKqrhjclxBq3lKzxUKYVVH7S7IruSUEmu7BaYW6YMaGRszt0mQoFqt++X61n4YlJxofPoT/gp1Zw/d4LR3q5ufBNt2qENi4OwJiVR3hh8lai4+59VUcgNiGRyX8ep/HwlTwzYQvtRq/jwjUHWdxuxy+wZLCx/ej7UKXrrdd880Gd543tZe8b09FL9nZ8HVw6DK7eUKGjubUEFLs1YkpXDQ0rPoLze8ErN7QaYfySa+cUZLIDmw0WD0p52b9og7vvX6Yl9PwdvHLB6e3ww6Op6ux3crLwarMyfNG5Mm7OTizec45OYzZwJuJGOn4zWUtMfCITNxyj0WcreWvWbk5dNf5bnYmI4flJW4lNsPMP/oOLYU6osV03DEJeun2fkJeMFYgv7INd0zO3PrE/N5t8K3YCdx9zawF46B9XDQ9m0lw29ur4BuPqKkDrryBHHnPrSSUFmexg5Sfw51hju90YKN3i3u8Jrgm9l0DOonDlmBFmTm6659sAOlQryC99a5PL2429ZyJpM2odO09eTXP5WdGNuER+XHuUhp+u4J05ezgTEUNeX3fea12OBS82wMfDha3Hr/DO7D32u/L4iT9hek+jSbzSk/DoXfoMPHP+o//qY+PStWRP0Zdh7xxj2+zbSjf5BOmqIRhtBLOfB2xQuSuUbWV2RammIJPVbRwDq5Kath4bDpWfSP17cxU3wkz+anDjMvzUGvbNS9VbqxcOYHZoCKXz+nDhWiydv93AvF2n0/ANZC3RcQmMW32EBp+u4P15ezl/LZb8fh580K4Cq15tTK+QopTL78vILlVxssC0LSf5af0xs8u+3fl9MKWzMTSzZFOjL+a/RjXUeg5yBEHECdgyPvPqFPuya7oxEV3eisa/K/bi5lXD83shfKbZ1ZhjyWDjl1bfgtDiE7OruS8KMlnZ9smw6A1ju/HbRv/L/cqRB3rNM+ZcSIiB6d1h03epemtwgBczX6jLw2UCiU2wEjZlO18tPWS/Vxgy0PXYBL5ZeZj6w1bw8YL9XLweS8GcngztUJGVrzame53CeLg6J+/fqHQgb7QwGrE/mL+PdYcvmlX67a6ehJ87QMxVKFgTHp9gLMj3X9y8oNHrxvbqz4wpACR7sdmMQQRgXI2xp94Lz5y3bouu+AgS4sytJ7MdWgpbfjS2231jhDoHoiCTVe373WjuBaN3oeHAtB/LzRuemAzVe4HNCgsGGssaWK33fKuPhyvf9ahB7/pFAfhy6UFemrqDmPjscfk2MiaekcsOUX/Ycj5ddIDLUXEUzuXFp50qsWJgI7rUKoSby53/N3y2QTE6VC1AotVGv8nbOH4pKpOrv4OoSzCpA1w7DblLQ9fpxs9HalTtbjRXRl+EDd9kbJ1if/7eYlzxcPGEio+bXc3taj8POfIak4TeDFzZQfTlW58VtZ+HYg+ZW08aKMhkRUdWwMxnjNBR9Slo+uGD//bj7GJ0sD/8tvH1uhEwq2+q+h2cnSwMblWOoR0q4uJkYe7O0zw5biPnrznYEOP7EBEdz5dLDhLyyXI+X3KQq9HxFMvtzRedK7Ps5YfoXCMYV+f//t/PYrHwcYeKVA72J+JGPM9O3ML1WBNHgcVFGbeTLh4E3wLQ/TfwCkj9+51db/38rB8JUXZ0lUky3tYJxp/l24Gnv4mF3IWb961VnVd9avy8ZwcLXoVrZyBXCXjkXbOrSRMFmazm5GaY2g0S46BsG2j9dfpdwrVYjP/R240x5l4InwGTOkJMRKre3qVWISb2roWfpys7Tl6l3ah17D0dmT612YkrUXEMX3yAkGHL+WrZIa7FJFAyMAdfPVmFJS8/RIdqBXG5R4D5Jw9XZ8Z1r548e/L/pu0wZ36exHiY3sOY6dMzJ3SflbZJssq1h3yVIe4arPki/esU+xQTCXt+M7Yzc4HI+1WtJ/gXhqjztwZIZGW7f4PdM43RrO3HZf5SEelEQSYrObfHWHogPgqKPwwdvwcn53u/735V6Zp0SyEHHFsDP7aAiFOpemu94rmZHRpCsdzenI6IodPY9SzZey79a8xkF6/H8snC/YQMW86oFYe5HptAmSAfvulWjcUDGtK2SgGcndIWKPP6evBt9+q4uTixZO85vlx6MJ2rvwerFWb3MyYNc/WCrjMgT+m0HcvJ6dZvfZu/M/ptJOsLnwHx0cbtyEJ1zK7m7lzcoPFbxva6r+DGFXPryUjXzsL8l43tBi9DwTvMK+YgFGSyist/GYtAxlyFgrWSJrVzz7jzlXgEnl5ojEQ5vwe+b2IEqVQomtubWf1CCCmRi+i4RPr+vIVvVx1xyCbg89di+HDeXhoMW8HYVUeIjkukfH5fvu1enQUvNuCxivlwSmOA+aeqhXIytL0xlfvI5YczbwSYzQZ/vAXh042rcJ1/NobmP4jiD0ORBsZVw5WONTpC0shem3zvpGInCCxvXGleO8LsajKGzQZzXzSCWlAlYwZuB6YgkxVEnoGJ7eD6OchbAbrdRwPmg8hXCfosMX7LunYafmxuLH+QCn5erkx4uhbdahfCZoOhC/fz2sxdxCXcu4HYHpyNiOG9uXtoMGwF3689yo34RCoX9OOHnjWY178+zcoHpUuA+aeO1QvybAOjaXrgjJ3sPpW6W3oPZO2XsDGpMbfdGCjZ5MGPeXM5DDDW3Dm//8GPKfbr9A44sxOc3Yz5huydkzM8kjRT9Z/fGlcuspptE+HQYuPvpP23xpUoB6Yg4+iiL8PP7YxO+4Bi8NRvRg9DZvEvBM8sgkL1IDbSGJa7a0aq3urq7MSH7SrwXutyOFlgxta/eeqHP7kcZb9DH09dvcHg2btp+OkKJqw/RmyClWqF/JnwdE1mh4bwSNm8WDLwN843WpSlYak8xMRb6TtxS8YuY7DtZ1g2xNhu9jFU6px+xy5Yw1jHxWbVgn1Z3c2rMWVbg3cuc2tJrVLNjSvbCTeMxt+s5MoxWPymsf3wYMhbztRy0oOCjCOLvWY0217YDz75jZWsffJmfh1eAUbzZ7l2xkJjv/UxLsmm4laRxWKhV0hRfuxVEx93FzYdvUy70es4dM6+5hk5eTmaQb+F0+izFfy88ThxiVZqFQlgcp/a/PpCPRqVDszQAHOTs5OFkV2qJvcYvTBpa8Zcxdq/AH5/0dgOGQB1Q9P/HA8PNhYo3T/PaFKXrCcu6tYvNvbc5Ptv/7xquO0n49Z9VnCz3y3uuvHLZ0b8f20CBRlHFR8Dv3SB09vAMwB6zIachc2rx9UDOo2HOkn/Yyx9Fxa+lurpvhuVDuS3fvUIDvDkxOVoOnyznlUHL2Rgwalz/FIUr83cSePhK/ll0wniE23UK56LqX3rMP35uoSUyJ0pAeaf/Dxd+a5nDXzcXdhy/Arvzt2dvv1Fx9fDzKeNqyVVnrr1D3p6CyxjTIUOsPQ9LdiXFe3+zRihlrOo0RflSIqEQIkmYE0wltbICjZ+Yyza6eptTHyXEYNBTKAg44gSE4x5Yo6tATcfeOrXtI8iSU9OTtD8Y+M2BBbYNM4YshufukUjS+b1YXa/EGoWycm12ASeHr/JtOn5j1y4zsvTd/Dw56uYvuVvEqw2GpTMzYzn6zLl2TrUKWbuJfLieXLwdZeqWCzwy6aT/LzxePoc+NwemPKkMYtzqRbGwnEZGdQavWHcpz++Fo4sy7jziDlu3laq1uO/l7CwV4+8Y/wZPhPOhptby4M6v89YSwqg2UcQUNTcetKRA/5kZXNWq7Ha8IH54OwOXX6BAna0ZgkYlysfH2/Ut38e/NTGmBE2FXLlcGdSn9p0rFYQqw3enbuHwbN3E5+YOU3Ah85d46Wp23n0i1X8tu0UiVYbjUvn4bd+9fi5d21qFrmPCeAyWOMygbzR3FjGYMjve1n/oMsYXDlu9DjFRkBwHej0ozERYkbyD4aaSUtnLB2SqtmixUGc2wt/bzZGu1XpZnY1aZOvMpTvANhgmQP3ciXGw6znjHWuSjxqzNKehSjIOBKbzVg7addUYwKjzj9BUTu9XFu+vXG7y8Mf/t4EPzaFy0dT9VZ3F2eGP16JN1qUwWKBnzce5+nxm4m4EZ9h5e47E0no5G00HbGaOTtOY7VBk7J5mRsWwvina1GtUCY2UN+Hvg2L0f7mMgZTtnHiUnTaDhR10Vh64PpZCCwHXadm3uRYDV42riye3QV7Z2XOOSXj3bwaU7qFOb176eXht41/bw8thhMbza4mbVZ/Zowc8/CHNiPtfwj8fVKQcSQrh8KmbwELtB9r/ANhzwrXg95/gF8huHQYfngUTm1L1VstFgvPP1ScsU9Vx9PVmbWHL9L+m3Ucu5i+04bvPhXBcz9vocVXa5gffgabDZqXD2Je//p837MGlQr6p+v50pvFYmFoh4pUKujH1eg0LmMQe82YSPHSYePv6qlfM3fkm3duqNff2F7+ofHbozi2+BjYOdXYrtbL1FIeWK7ixlIvYFw1dLRerlNbYfVwY7vVF+Cbz9x6MoCCjKPY8A2sGmZsP/ZZ+g6FzUh5ShtzzQRVhKgLMKEVHPwj1W9vVj6ImS/UJZ+fB39diKLdN+vYcCR1t6n+y86TV+nz02ZajVzL4j3nsFigVaV8LBrQgLHdq1OhgOOs/mosY1CDPD7uHDh3jZfvZxmDhDiY9hSc3g5euYz1k3zzZ2zBd1K3H3jlNkaHbP85888v6WvfXGNyTr9gKN7Y7Goe3EOvg4sHnFhvzHDtKOJvwKznwZZo3CKr0NHsijKEgowj2D4JFg8yth9+G2o9a24998snyJgFuPjDxvIJvzxpTMiUSuXz+zEnNITKwf5cjY6n+w9/Mm3ziTSVsvX4FXqN30Tb0etYuu88ThZoVyU/S/7XkFFdq1EmyDdNxzVbkF/SMgbOTvyx9xwjUrOMgdUKs5+Hv1Yaoxi6zYDcJTO81jty97m1YN/KYRCXxltkYh+2Jt1Wqto9a4yM8Stw699dR+rlWva+schrjiBo+bnZ1WQYBRl7t3cuzE267F43DBoMNLeetHL3MdZnqtzV+O1gbn9jSGMqL9MG+nowrW8dWlXKR4LVxuu/hvPR/L0kpvLKw6ajl+n+w590HLOelQcu4OxkoWO1gix9+SFGPFmVEoE+D/Ld2YVqhXLycQdjGYOvlx9m/q4zd9/5Zr/V7l/ByRWe+BkKmLzWSo2njVtb188m3UIVh3TxkDEKzeJ065ZMVlD/ZXD3hXPhtxbAtGdHV9+albvNyPtbqd7BKMjYsyMr4NfexnweVbtD0w8du0nL2dWYu+Dmuh6rhsGcsFT3RHi4OjOyS1UGNDGuGny35ih9/6MnxGazsf7IRZ4ct4HO325gzaGLuDhZeKJGMMtfeYjPO1emWJ4c6fKt2YtO1QvSp/6tZQz2nL7LMgZrht8KC+3HGmtnmc3FHRonzTi69susvWBfVnazybfEo8aVjKzCK+BWL9eKj+y7lysmwpj4DowRSqWamlpORlOQsVcnN8PUbsbCeuXaZvx8HpnFYoGH34JWI4zf2HZMgilPGA2nqXq7hQFNSjGyS1XcXZxYtv88ncas5+8rt25F2Gw21hy6QOdvN9D1uz/Z+NdlXJ0tdK1diBUDGzGsUyUK58qEtahM8kaLMjQomZsb8Yn0nbiVi9f/tYzB1glGUy1A82HGInn2olJnY9RUTISx+rA4loQ42PGLsV3dgWbyTa06DtLLtehNiDgJ/oWNX4CzOAUZe3RuD0zuaPSTFH8YOnyXNe4z/1ONp+HJX8DVy5gIbfxj97U4W+vK+Zn2XF3y+Liz/+w12o1ex9bjV1hx4Dwdxqyn+w+b2HzsCm4uTvSoW5hVrzbm4/YVCQ7IpCHFJnJxdmJUl2oUze3Nqas36Ddp261lDPb9DvP+Z2w3eAXqPG9eoXfi5HxrErKNY40FUcVxHJgP0ReNnoySzcyuJv2557jVy7Xq01RP9pmp9i8wfkG8ObrV3fFvm9+Lgoy9uXQEfm5v/EYaXBuemGRccs+KSjeHXvOM33DO7oLvH4ULqWhSTVIl2J85oSGUy+fLxetxdByznqfHb2b7iau4uzjxTEhR1rzWmPfbViC/v2cGfiP2x8/Lle96VCeHuwubjl3m3bl7sB1dAzOTblVW62GsdWSPSjU3fvYTbsDqLLZgX1aX3OT7VMZPpmiWm71c184Ys5fbk6iLt9ZIqxdmTIGRDSjI2JPI08ZK1tfPQd4K0HUauGXdWyCA0WDaZwkEFIeIE8ZcM8c3pPrt+f09mfF8XZqWMybc8nR1pm/DYqx5vTHvtC5HXl+PjKrc7pUI9OHrLlWwWGDn5tXET37SmNmzTCto+aX93qr854J9W38ywr3YvyvH4K8Vxna17qaWkqFc3KFx0ijSNV/AjaumlpPMZoN5A4xpLvKUhcZvm11RplGQsRfRl40rMVdPQEAxYzXpzJyUzEwBxYyJ8wrWNOaemNgW9s5J9du93V0Y+1R1pjxbm7WvN+bNx8oS6JN9A8w/PVwmLx80zMFPbsNwS7hOZGBN6Pi9/f+2XLgelGxqjHBb8ZHZ1UhqbEvqGSnWGHIWMbWUDFfpCchTxvj3av1Is6sx7Jpu3Dp2coEO3xoL+WYTCjL2IPYaTOoIF/aDT37oMQdyBJpdVebyzg095kLplsZVg+k9jR6JVHJyslCveG5y5ciit+HS6vp5uh18iTyWCPZZC9HyQignrznIzKQ3e2V2/2pMry72KzHBmO8KsmaT7785ORtzegFsHAPXz5tbT8TfsCCpd+ehN4w1orIRBRmzxcfAL13g9DZjZtUes8G/kNlVmcPNy5jPpEZvwAaLXofFbznO5FP2JiYSJnXEcuUoVr9CDM31ESdvuPHsxC1E3e8yBmYIqggVHze2b67aK/bp0GJj/h+v3MYvI9lBmVbGrfH4qFtLAJjh5kLCsRFGPfX/Z14tJlGQMVNiPMx8Go6tMRbNe+pXY0r/7MzJ2ZiB8maPxIZRxlw6CbH/+Tb5l4RYmNbNaKL2yo1Tj9kM6/UouXMYo7xenn4fyxiYqfGbxqXyw0vh6Bqzq5G7udnkW6ULuLiZW0tmsVjgkXeN7S0/Gj1CZtjygzE7t4sHtP/W/m8bZwAFGbPcTNEHFhg/gF2nQv6qZldlHywW47eKDt8Zs87u+Q1+7qAJ0lLLmgi/PWvM7OmWA56aCbmKk8/PM3kZg8V7zvHVskNmV3pvAcWMCb0Aljnggn3ZQcQpOLzE2Hb0BSLvV7GHoFgjsMbDyk8y//yXjsAfSaMPmwwxb4kRkynImMGWdNtk1zTjt83Hf4Ii9c2uyv5U6mx8CLv7GlOe/9gcrp40uyr7ZrMZ98r3zgFnN3hycoqAXL1wTj5sXwGAr5YdYmG4A8zT0vBVY76hvzfD/vlmVyP/tn2SMaS/cH3IXcLsajLfzV6unVPh3N7MO29iAsx6zpimoGhDqNU3885tZxRkzLDi46T5ByzQbqwxn4rcWbFGxoKTPvmNZugfHoWz4WZXZb9WDTMuNWOBDuOM/37/0rlGMM+EGMsYvDx9J3tPR2ZujffLJwjqvGBsL3vfuOIk9sGaeGuG2+zQ5HsnBapD2TaA7daM2Zlh/VdGuHf3hbbfgFP2/TjPvt+5WTaMvjXJV8vhUOlxc+txBEEVjLlm8pQ1JqH6sYWxDpWktPkHWDnU2H7sMyjf/q67vvnYrWUMnp24hUv/XsbA3tR7ETz84eIB4zdfsQ9HVhhT4Xv4J32YZ1MPv20suXJgvrG8TEY7Gw4rkv5fbzEM/IMz/px2TEEmM237GRYnLYr38GCo2cfcehyJX0F4ZhEUaQBx12ByJ32g/dOe2TD/FWP7odeh1rP/ubuLsxMju1SlSC4vYxmDyduIT7Tj0WGe/tDgZWN75VBjtJ+Yb9sE48/KT2areUtuk6c0VO5qbGd0L1dCLPz2nNGXU7olVO6ScedyEAoymWXvnH9MHd3fWOdG7o+nvzGyq0JHsCbdH17zuRpA/1plNPdig+pPQ6NBqXqbv5cb3/esQQ53F/48epkhv+/J2DofVK2+4JPPuAKw5Uezq5Fr5+DAQmO7Wja9rfRPjd4w+tKOrbk1w3FGWPExnN9jDHXPKosJPyAFmcxweFnKNW4e/UA/fGnl4g4dvoeQl4yvl70P8182Gt+yozM7b62SXraNMXT9Pn62SgT68NWTxjIGkzaeYNLG4xlY7ANy9TQ+LADWDDfmyRHz7Jhs/EJRsCbkLWd2NebzD751lX1pBl2VObER1n9tbLceATnypP85HJCCTEY78SdMe8q4DFiuHbQaoRDzoJyc4NH3ocVngMX47XzaUxAXZXZlmevSEWNG6Lhrxi23NK6S/kjZvLzazJi/6L25e9j416X0rjT9VHkKcpWA6EtGv5mYw2qFbRONbV2NuaXBK8aUB2d23NcyK6kSex1mPW/8Qly5C5Rtnb7Hd2AKMhnp7G6Y8jjER0PxR9L8QSN3UbuvMROwiwccXAg/tYbTO7LH1Zlr52BSB2OBuKCK8OSUB+pReOGh4rSpnJ8Eq41+k7dx8nJ0Ohabjpxdbq3avWEUXL9gbj3Z1bE1cOWoMZFnhQ5mV2M/vHND3TBje/mH6ftv0ZJ3jP/mvgWguQlz1tgxBZmMcumIsQhkTAQE10n6wM0mM15mprKtjTWaPHPCqa0w7iEYWhB+aAaL3oTwmXD5aNbqo4mJMK7EXDlmLM7X7Vfw8H2gQ1osFoZ1rESFAr5cjoqz72UMyrWFfFUg7rrRIyWZb1vSTL6VHgc3b3NrsTd1Q8EzAC4dgp1T0ueYh5cmTasAtB1t9AtKMgWZjBBxCia2g6jzkLcidJ2m/9kzUqHa0HsJlHjUmFMh4Qac3AgbRxvLG3xdBT4tBpM6GUMWD/4BURfNrjpt4mPgl65wLhy8A41V0n3ypsuhPd2cGde9RvIyBgNn7LTPZQwslltLWGz5Aa7YcV9PVhR1yVhlGXRb6U48fG8N5lj5yYOPsLtxBeYkXeWp1ReKN36w42VBFpstK/2qervIyEj8/PyIiIjA1/fBfmtNlahLML6FMd9FQHFjyHB2W8naTFYrXDpsXJ25+TgbbvQo/Zt/YWMyqwLVjD/zVbbvwGlNhOk9YP8845L+0/MzZJXbrccv8+S4jcQn2vhfk1K81MROpz3/qQ0cXWUMe20/xuxqso8No41pJPJVhudWm12NfYqPgZHVIPIUNPvYuEqTVr/2gfAZRm/Yc2uMxXWzidR+fivIpKeYSKNP48wO4z7mM4uy70rW9iQh1uhXOrXVWGX81Fa4ePD2/SxOEFjuVrApUN2YhM8eFmGz2eD3l4xL+s5uxjD0og0z7HTTN5/ktV93ATD2qWo0r5Avw86VZqe2wncPAxZ4Yb1GzmQGmw1G1zL+/2n5BdTsbXZF9mvbRJjb37jN9NLOtN3+3TMLZvQy/m165g8IrpnuZdqz1H5+28G/0FlE/A34pYsRYrxyQffZCjH2wsUdClY3HjfduGr8XZ3aCqe2wd9b4PpZOLfbeNwckeHiCfmrpLxy418480eerfgoqS/BAh2/z9AQA9C5ZjB7z0QyYf0xXp6+kyK5vSkTlAlXNO/Hzanh9801Giu7pFM/gtzdiY1GiHH1goqalfw/Ve4K6742emU2jIbGqZvfKdm1czAvaRLI+i9nuxBzP3RFJj0kxhvDfw8uMi759/pdK1k7osjTKW9Jnd4BsXeYq8QrF+T/x1WbAtWM0QoZ5c9vYeFrxnarL6HGMxl3rn9ISLTSa/xm1h6+SMGcnswNq0+At501rF84CN/UNoak9l4CwbXMrihrm/U87PzFGAbfTsPf72nPbJjR0xiS/dLO1P87YbPBL08anylBFaHP8mw5WES3lpJkeJCxWmFWX+MeposHPPUbFAlJ//NI5ktTv031f/TbpMO97N2/GpMpYoNGb0Kj1x/8mPfhanQcbUev4/ilaOoUC+Dn3rVxdbazMQJzwoyFCwuHQK/5mqcpo9y4Cp+XMZrpey/VFYLUsNlgXCPj6m+dUGj+cered/O2lLMb9F0JectnYJH2S0EmSYYGGZsNFgyEzd+Dk4sxl0epZul7DrEv/+y3ufm4dOj2/SzOd+i3KXN//TZHlsPkzkZwqvmssRCkCR/SB89do/3odUTFJdK9TmE+aFch02v4TxF/w9fVIDHWGIpesonZFWVNm74z/r0LLGf0JCkwps7hZcacT85u0H/bvRd4vHIMxoQY0ws0GQL1B2RGlXZJQSZJhgaZZR8YU6Xf7Fuo2Cl9jy+O4W79Nv/m6mXMf1Kg2r37bU5tgwmtID7KmBG604+mTqa4dO85nv15CzYbfNy+Il1r21n/1+K3jAnygipC39XG7M+Sfmw2GNvAGPbffBjUed7sihyHzWYMAjm2Bqo+ZcwDczdWq7Hv8bXG/GNPL8jWk6gqyCTJsCCzfiT88baxre59+bd/99uc2m4sJfBvXrlS3pLKX82YN+LHpsY0/EUfgm4zjIZlk41ecZjPFh/AxcnC5D61qV0sl9kl3RJ9Gb6qbPQ0dfxBv1Skt5sjxJzd4ZX94BVgdkWO5eRm+KGJMfqo35+Qp9Sd97s5tN3VG15YCwHFMrdOO6NRSxnJZoOLSbcTHnlHIUZu55vfeNxcD8VqNW5B3bxqc7PfJvoSHPrDeNzk7G7cJslXGZ6cbBchBqBfo+LsOxPJvF1neGHyNuaGhVAwp53MaeEVAPVehBUfGiOYyrUFZ1ezq8o6tibN5FuurUJMWgTXhNIt4cB8WP6BMdP7v53fbyw2CdDsw2wfYu6Hrsiklc1mfPiUbKp7xZI2/9VvE1DMmDfCzla3vRGXSKex69lzOpKy+Xz59YW6eLnZye9Dsdfh66rGjNotP7+1ErE8mNhrMLy0cZuz13woUt/sihzTub0wph5gg2dXGLeXb0qMh++bGLeoSzSBbjP1uULqP791IzmtLBajsVc/bJJWN+e3qd0XOnwL/bfA68fh6YXw7HK7CzFgLGPwXY8a5M7hxr4zkQycsRO7+V3IPQc8lDRMfdWn2W819Iyy+1cjxOQqYYwMk7TJWw4qP2lsL3s/5WurhxshxsMf2ozU58p9UpARsSee/lC4nrEIpp3K7+/J2Keq4+psYUH4WUYuP2x2SbdU62k0UF8/B3+ONbuarOHmbaVqPfQB+6AaDQInV/hrBfy1ynju1FZY/Zmx3fJz45a03BcFGRG5bzWKBPBh0jDsL5YcZPGeO4zSMoOLGzyc1IS/9iujCVjS7my4sayHk6sxU608mJyFocbTxvayIRAXbUwyaEuE8u2hQkdz63NQCjIikiZP1CxEr3pFAHh52g4OnL3DqCwzVOgEeStAbASsG2F2NY7t5tWYMi3t8lanQ2r4qjEq6dRWmNjGWPIhR15j9KuueKWJgoyIpNlbLctSr3guouIS6TNxM1ei4swuyZhD5pF3jO0/vzWGwsv9i4uGXdON7eo9za0lK8kRCHVeMLb/3mz82WakRoM9AAUZEUkzV2cnRnetRqEAL05evkG/yduIT7SaXZYxmrBQXUiIgVXDzK7GMe2dY1zV8i8MRRuZXU3WUq+/0dgLRu+RZoR/IAoyIvJAcnq78V2PGni7ObPhr0t8OG+v2SUZl+gfedfY3vYzXLSjhmRHsXWC8We17popOb15+sPj4425j5oNNbsah6efThF5YKWDfPjyiSoA/LThOL9sOmFuQQCF60Kp5kYj5YoPza7GsZzfDyc3GmuGVXnK7GqypuIPQ9MPjGkD5IGYGmSGDh1KzZo18fHxITAwkHbt2nHgwIE77muz2WjRogUWi4XZs2dnbqEick9NywfxyqPG1OvvzNnN5mN2MGLo4cGABfbMgtPbza7GcWybaPxZqhn45jO3FpF7MDXIrFq1itDQUDZu3MiSJUuIj4+nadOmREXdPpHViBEjsKijW8SuhT1cgpYV8xGfaOP5n7dy6uoNcwsKqgCVOhvb/56ETO4sIRZ2/mJsV+9laikiqWFqkFm0aBG9evWifPnyVK5cmQkTJnDixAm2bt2aYr8dO3bw+eef8+OPP5pUqYikhsVi4bPHK1Euny+XouLo9t1Gwv+OMLeom5OQHVl+axIyubt9v8ONy+BbwJguX8TO2VWPTESE8Q9eQMCtYWjR0dF07dqV0aNHExQUdM9jxMbGEhkZmeIhIpnHy82F73rWIL+fB8cuRdNhzDrGrjqC1WrSUgYBRVNOQmYvSyrYq21Jc8dUfQqcnM2tRSQV0hRkTp48yd9//5389aZNmxgwYADjxo1LcyFWq5UBAwYQEhJChQoVkp//3//+R7169Wjbtm2qjjN06FD8/PySH8HBwWmuSUTSpoC/J/NfbEDz8kHEJ9r4ZOF+uv/4J2cjYswp6J+TkO2fZ04NjuDSETi6GrAYQUbEAaQpyHTt2pUVK1YAcPbsWR599FE2bdrEW2+9xfvvp+0+dGhoKLt372bq1KnJz82dO5fly5czYsSIVB9n0KBBREREJD9OnjyZpnpE5MHk9HZjzFPV+KRDRTxdnVl3+BLNv1ptznIGOQKhbj9je9kHkJiQ+TU4gptNviUeAf9C5tYikkppCjK7d++mVq1aAEyfPp0KFSqwfv16Jk+ezIQJE+77eGFhYcybN48VK1ZQsGDB5OeXL1/OkSNH8Pf3x8XFBRcXFwA6duxIo0aN7ngsd3d3fH19UzxExBwWi4UnaxVi3ov1qVDAl6vR8Tz381YG/RZOdFwmh4l6/cEzAC4egF1T771/dpMYDzumGNvVNJOvOI40BZn4+Hjc3d0BWLp0KW3atAGgTJkynDlzJtXHsdlshIWFMWvWLJYvX07RokVTvP7GG2+wa9cuduzYkfwA+PLLLxk/fnxaShcRExTPk4PfXgjhuYeKYbHAL5tO0GrkWnafysRGYA8/aPCKsb1iKMSbdJvLXh1YCFHnwTsQSrcwuxqRVEtTkClfvjxjx45lzZo1LFmyhObNmwNw+vRpcuXKlerjhIaGMmnSJKZMmYKPjw9nz57l7Nmz3LhhDNkMCgqiQoUKKR4AhQoVui30iIh9c3NxYlCLskzuXZu8vu78dSGK9t+sY9zqTGwErtnHGI0T+Tds+SFzzukokpt8u4Gzq7m1iNyHNAWZYcOG8e2339KoUSO6dOlC5cqVAaOn5eYtp9QYM2YMERERNGrUiHz58iU/pk2blpayRMQB1CuRm0UvNaRZ+bzEJ9r4eMF+evy4iXORmXCFxNXDGI4NsHo4xGhUIwBXT8DhZcZ2tR7m1iJynyw2W9rGIiYmJhIZGUnOnDmTnzt27BheXl4EBgamW4EPKjIyEj8/PyIiItQvI2JHbDYbv2w6yfvz9hATbyWnlyvDOlaiafl7T7PwQBITYExduHgQGr4GD7+VsedzBCs+NhbXLNoQev5udjUiQOo/v9N0RebGjRvExsYmh5jjx48zYsQIDhw4YFchRkTsl8VioWvtQszr34Dy+X25Eh1P35+38uascG7EJWbciZ1dkpYuADaMhuvnM+5cjsCaCNsnGdtq8hUHlKYg07ZtWyZONIbpXb16ldq1a/P555/Trl07xowZk64FikjWViIwB7/1q0ffhsUAmPLnCVqNXJOxjcBlW0P+ahAfZdxiys4OL4XIU8aIrrKtza5G5L6lKchs27aNBg0aADBz5kzy5s3L8ePHmThxIl9//XW6FigiWZ+7izNvPlaWSb1rE+jjzpGkRuDvVv+VMY3AFgs0ec/Y3vIjXDmW/udwFFsnGH9W7gIu7qaWIpIWaQoy0dHR+Pj4APDHH3/QoUMHnJycqFOnDsePH0/XAkUk+6hfMjeLBjTk0XJGI/BHC/bRc/wmzmdEI3Cxh6BYY7DGG8Oxs6PIM3BwsbFdXbeVxDGlKciUKFGC2bNnc/LkSRYvXkzTpk0BOH/+vBpqReSBBHi7Ma57dT5qXwEPVyfWHLpIsxGrWbL3XPqf7JF3jD93TYNze9L/+PZuxySwJUJwHchT2uxqRNIkTUHmnXfeYeDAgRQpUoRatWpRt25dwLg6U7Vq1XQtUESyH4vFQrfahZnXvz7l8hmNwM9O3MLbs9O5EbhANSjXDrAZSxdkJ1YrbPvZ2K7ey9RSRB5Emodfnz17ljNnzlC5cmWcnIw8tGnTJnx9fSlTpky6FvkgNPxaxLHFJiQyfPEBvltzFDCag79+sirl8qfT/88XD8Ho2saViWcWQ6E66XNce3dkOfzcHtz94JX94OZldkUiKWTo8GswZt2tWrUqp0+fTl4Ju1atWnYVYkTE8bm7OPNWy3L83LsWgT7uHD5/nXaj1/H9mnRqBM5d8tZKz0vfg7T9bud4tibN5Fups0KMOLQ0BRmr1cr777+Pn58fhQsXpnDhwvj7+/PBBx9gtVrTu0YRERqUzMOiAQ1pUjYvcYlWPpyfjo3AD70OLh5wYgMcWvLgx7N31y/A/vnGtpp8xcGlKci89dZbjBo1ik8++YTt27ezfft2Pv74Y0aOHMngwYPTu0YREcBoBP6uR3U+bHerEbj5V2tYtu8BG4H9CkCtvsb2siFG/0hWtnOKMVorfzUIqmh2NSIPJE09Mvnz52fs2LHJq17fNGfOHPr168epU6fSrcAHpR4Zkazp8Plr9P9lB/vOGOslda9TmLdalsXD1TltB4y+DF9VgdgI6PA9VHo8/Yq1JzYbjKoBlw5D66/U6Ct2K0N7ZC5fvnzHXpgyZcpw+fLltBxSROS+lAj0YXZoPXrXLwrAzxuP03rk2uRgc9+8AqD+S8b2ig8hIS6dKrUzx9cZIcbVGyp0NLsakQeWpiBTuXJlRo0addvzo0aNolKlSg9clIhIari7ODO4VTkmPlOLPD7uHDp/nbaj1vHD2qNpawSu/TzkyGvM9Lvtp3Sv1y7cbPKt2AncfcytRSQdpOnW0qpVq2jZsiWFChVKnkNmw4YNnDx5kgULFiQvX2APdGtJJHu4dD2W12buYtl+YxHIhqXyMPzxSgT6eNzfgTZ/D/NfAe9AeGkHuHmnf7Fmib4Mn5eBxFh4djkUqG52RSJ3laG3lh566CEOHjxI+/btuXr1KlevXqVDhw7s2bOHn3/+Oc1Fi4ikVa4c7nzfswYftC2Pu4sTqw9eoMWINSzff5+NwNV6Qs6iEHUeNmaxRXB3TTdCTN6KRqOvSBaQ5gnx7mTnzp1Uq1aNxMR0nHnzAemKjEj2c/DcNV78ZTv7z14DoEfdwrz52H00AofPhF97g7svvLTT6J9xdDYbjKkH5/fCY8Oh1rNmVyTynzJ8QjwREXtVKq8Ps0NDeCbEaASeuOE4bUatZf/ZVDYCl+9gXLWIjYS1X2ZgpZno781GiHHxhIpZdESWZEsuZhcgIpIRPFydead1ORqWys3AGbs4eO46bUatY1CLMvSqVwSLxXL3Nzs5QZN3YXIn2DTOaAL2K5DxRdtsYE0Ea0LSIz7l14n//Do+6c/EpOcT7vxITPpz90zjHOXbgad/xn8vIplEQUZEsrRGpQNZNKABr83cxfL95xny+15WHbzAZ50qk8fH/e5vLNEECocYw5V/7Q15K9w7LNz2/F2CR/JrN7/+RxDJaNU0k69kLffVI9OhQ4f/fP3q1ausWrVKPTIiYndsNhs/bzzOR/P3EZtgJXcONz7rVJnGZQLv/qYTf8KPTTOvyLuxOIOTi/Fwdrm1/e+Hsys43dzXNelP56TnXSB/VWM5hv+6GiViJ1L7+X1fQebpp59O1X7jx49P7SEznIKMiPzTvxuBe9Urwhstyty9ETh8Jpzbkz5B4o7v+efX/3j/zfdYnI1bXSLZTIYEGUekICMi/xYTn8iwRfsZv+4YAKXz+vB1l6qUDtIEcSL2QqOWRETuwsPVmXdbl2f80zXJncONA+eu0XrUWiasO0oW/91OJMtRkBGRbKtx6UAWvtSQxqXzEJdg5b3f9/LMhM1cvB5rdmkikkoKMiKSreXxcefHXjV5r3U53FycWHHgAs1HrGbFgfNmlyYiqaAgIyLZnsVioVdIUeaGhVA6rw8Xr8fx9PjNvDd3DzHx9jMKU0RupyAjIpKkTJAvc8JC6FWvCAAT1h+j3eh1HEga4SQi9kdBRkTkHzxcnXmvTXnG9zIagfefvUYbNQKL2C0FGRGRO2hcxmgEblQ6D7FJjcBPT9jM+WsxZpcmIv+gICMichd5fNwZ36smQ9qUx83FiZUHLtB8xBqW7j1ndmkikkRBRkTkP1gsFnrWK8K8/vUpE+TD5ag4+kzcwluzwrkRp0ZgEbMpyIiIpEKpvD7MCQvh2QZFAZj85wlajlzD7lMRJlcmkr0pyIiIpJK7izNvtSzHpN61yevrzl8Xomj/zTrGrDxColWNwCJmUJAREblP9UvmZtFLDWlePoj4RBvDFu2n63cbOX31htmliWQ7CjIiImmQ09uNMU9V49OOlfByc+bPo5dpPmI1v+88bXZpItmKgoyISBpZLBY61wxmwYsNqBzsT2RMAv1/2c7L03ZwLSbe7PJEsgUFGRGRB1Qktzczn6/Liw+XwMkCv20/xWNfr2Hr8ctmlyaS5SnIiIikA1dnJ15uWpppz9WlYE5PTl6+weNjN/DFkoMkJFrNLk8ky1KQERFJRzWLBLDgpQZ0qFoAqw2+XnaITmM3cOxilNmliWRJCjIiIunM18OVL56owtddquLj4cKOk1d57Os1TN9yUus1iaQzBRkRkQzSpnJ+Fg1oSK2iAUTHJfLazF30m7yNq9FxZpcmkmUoyIiIZKAC/p788mwdXmteGhcnCwt3n6X5iDWsO3zR7NJEsgQFGRGRDObsZKFfoxLM6hdCsdzenI2Modv3f/LR/L3EJmi9JpEHoSAjIpJJKhb0Y96L9elauxAA3605SrvR6zl07prJlYk4LgUZEZFM5OXmwsftKzKue3UCvN3YdyaSViPXMnHDMTUCi6SBgoyIiAmalg9i0YAGNCyVh9gEK+/M2cMzEzZz4Vqs2aWJOBQFGRERkwT6eDChV03ebV0ONxcnVhy4QPMRq1m275zZpYk4DAUZERETOTlZeDqkKL+H1adMkA+XouLo/dMW3p4dzo04NQKL3IuCjIiIHSgd5MPs0BB61y8KwKSNJ2g1cg27T0WYXJmIfVOQERGxEx6uzgxuVY6fe9ci0MedIxeiaP/NOsauOoLVqkZgkTtRkBERsTMNSuZh0YCGNCufl/hEG58s3E+37//k9NUbZpcmYncUZERE7FCAtxtjn6rOJx0q4unqzIa/LtF8xGrm7TptdmkidkVBRkTETlksFp6sVYgFLzWgckE/ImMSCJuynVem7+RaTLzZ5YnYBQUZERE7VzS3NzNfqEdY4xI4WeDXbX/z2Ndr2Hr8itmliZhOQUZExAG4OjsxsFlppvatSwF/T05evkHnbzfw5ZKDJCRazS5PxDQKMiIiDqRW0QAWDmhAuyr5SbTa+GrZIR7/dgPHL0WZXZqIKRRkREQcjK+HKyOerMpXT1bBx92F7Seu8thXa5ix5aTWa5JsR0FGRMRBta1SgIUDGlCrSABRcYm8OnMXYVO2czU6zuzSRDKNgoyIiAMrmNOLX/rW4dVmpXFxsjA//AzNR6xh/eGLZpcmkikUZEREHJyzk4XQxiX4rV89iub25mxkDN1++JOhC/YRm6D1miRrU5AREckiKhX0Z/6L9elSKxibDb5d/RftR6/n8PlrZpcmkmEUZEREshAvNxeGdqjEt92rk9PLlb1nImn59Vp+3nBMjcCSJSnIiIhkQc3KB7FoQEMalMxNbIKVwXP20OenLUREa0ZgyVoUZEREsqi8vh789HQt3mlVDjcXJ5btP0/b0Ws5dE63miTrUJAREcnCnJwsPFO/KL+9UI8C/p4cuxRNu9HrWLznrNmliaQLBRkRkWygQgE/5oaFUKeYMefMcz9v5cslB7Fa1Tcjjs3UIDN06FBq1qyJj48PgYGBtGvXjgMHDiS/fvnyZfr370/p0qXx9PSkUKFCvPjii0RERJhYtYiIY8qVw52fe9emV70iAHy17BDPT9rK9dgEcwsTeQCmBplVq1YRGhrKxo0bWbJkCfHx8TRt2pSoKGPNkNOnT3P69GmGDx/O7t27mTBhAosWLaJ3795mli0i4rBcnZ14r015Pu1UCTdnJ/7Ye472o9dx9KLWahLHZLHZ0Xi8CxcuEBgYyKpVq2jYsOEd95kxYwZPPfUUUVFRuLi43POYkZGR+Pn5ERERga+vb3qXLCLisLafuMLzk7ZyLjIWHw8XRnapSqPSgWaXJQKk/vPbrnpkbt4yCggI+M99fH197xpiYmNjiYyMTPEQEZHbVS2Uk9/D6lOtkD/XYhJ4esJmxqw8ovlmxKHYTZCxWq0MGDCAkJAQKlSocMd9Ll68yAcffEDfvn3vepyhQ4fi5+eX/AgODs6okkVEHF6grwe/9K3DkzWN2YCHLdpP/1+2Ex2nvhlxDHZza+mFF15g4cKFrF27loIFC972emRkJI8++igBAQHMnTsXV1fXOx4nNjaW2NjYFO8LDg7WrSURkf9gs9mY9OcJhszdQ4LVRtl8vozrXp3gAC+zS5NsyqFuLYWFhTFv3jxWrFhxxxBz7do1mjdvjo+PD7NmzbpriAFwd3fH19c3xUNERP6bxWKhe53CTHm2DrlzuLHvTCRtRq3VKtpi90wNMjabjbCwMGbNmsXy5cspWrTobftERkbStGlT3NzcmDt3Lh4eHiZUKiKSPdQqGsDcsPpULODHleh4uv+4iR/XHlXfjNgtU4NMaGgokyZNYsqUKfj4+HD27FnOnj3LjRs3gFshJioqih9++IHIyMjkfRITtTS9iEhGyO/vyYzn69K+agESrTben7eXgTN2EROvf3fF/pjaI2OxWO74/Pjx4+nVqxcrV66kcePGd9zn6NGjFClS5J7n0PBrEZG0sdls/LD2KB8v2IfVBpUL+jG2e3Xy+XmaXZpkA6n9/LabZt+MoiAjIvJg1h66SNgv27gaHU/uHO6MfaoaNYrcfZoMkfTgUM2+IiJiv+qXzM3c0PqUCfLh4vVYuny3kSl/njC7LBFAQUZERFKhUC4vfutXj5YV8xGfaOPNWeG8OSucuASr2aVJNqcgIyIiqeLl5sKorlV5tVlpLBaY8ucJun2/kQvXYu/9ZpEMoiAjIiKpZrFYCG1cgh961sDH3YXNx67QeuRadp68anZpkk0pyIiIyH17uExeZoeFUDyPN2cjY3j82w38uvVvs8uSbEhBRkRE0qR4nhzMCg2hSdlA4hKsvDJjJ+//vpeERPXNSOZRkBERkTTz9XBlXPcavPhwCQB+XHeUHj9u4nJUnMmVSXahICMiIg/EycnCy01LM/apani5ObP+yCXajFrL3tORZpcm2YCCjIiIpIvmFfIxq18IhQK8+PvKDTqOWc+8XafNLkuyOAUZERFJN6WDfJgbFkKDkrm5EZ9I2JTtDFu0n0Rrlp5EXkykICMiIunK38uN8b1q8lzDYgCMWXmE3j9tJuJGvMmVSVakICMiIunOxdmJQY+V5asnq+Du4sTKAxdoN3odh85dM7s0yWIUZEREJMO0rVKAX1+oRwF/T45ejKL9N+v5Y89Zs8uSLERBRkREMlSFAn7MDQuhdtEArscm0PfnrXy19BBW9c1IOlCQERGRDJcrhzuT+tSmZ93CAHy59CDPT9rK9dgEkysTR6cgIyIimcLV2YkhbSvwacdKuDk78cfec7QfvY5jF6PMLk0cmIKMiIhkqs41g5n6XB0Cfdw5dP46bUatZeWB82aXJQ5KQUZERDJdtUI5mde/PtUK+RMZk8AzEzYzdtURbDb1zcj9UZARERFTBPp68EvfOjxZMxirDT5ZuJ8Xp+7gRlyi2aWJA1GQERER07i7ODO0Q0U+aFseFycLv+88Tccx6zl5Odrs0sRBKMiIiIipLBYL3esWYXKf2uTydmPvmUjajl7H+iMXzS5NHICCjIiI2IXaxXLxe//6VCjgy+WoOLr/sInx646qb0b+k4KMiIjYjfz+nsx8vh7tqxYg0WpjyO97eXXmLmLi1Tcjd6YgIyIidsXD1ZkvOlfm7ZZlcbLAzK1/88S4jZyNiDG7NLFDCjIiImJ3LBYLfRoUY+IztfHzdGXnyau0GrmWrccvm12a2BkFGRERsVv1S+bm97D6lAny4eL1WJ4ct5HJfx5X34wkU5ARERG7ViiXF7++UI/HKgYRn2jjrVm7eeLbjew+FWF2aWIHFGRERMTuebu7MLprNQa1KIOHqxObjl2m9ai1DPotnEvXY80uT0ykICMiIg7BYrHw3EPFWf5KI1pXzo/NBr9sOkGj4Sv5Ye1R4hOtZpcoJrDYsviNxsjISPz8/IiIiMDX19fsckREJJ1sOnqZIb/vYc/pSABKBObgnVblaFgqj8mVSXpI7ee3goyIiDisRKuN6VtO8tniA1yOigOgSdm8DG5VlsK5vE2uTh6EgkwSBRkRkawv4kY8Xy09xMQNx0iw2nBzdqJ3g6KENi5BDncXs8uTNFCQSaIgIyKSfRw+f4335+1j9cELAAT6uPN68zK0r1oAJyeLydXJ/VCQSaIgIyKSvdhsNpbtO88H8/dy/JKxinaVYH/ea1OeKsH+5hYnqaYgk0RBRkQke4pNSOTHtccYtfwQUXHGWk0dqxXk9ealCfT1MLk6uRcFmSQKMiIi2dv5yBiGLTrAr9v+BsDbzZn+j5Tk6ZAiuLs4m1yd3I2CTBIFGRERAdh+4grv/b6XnSevAlAklxdvtyzHI2UDsVjUP2NvFGSSKMiIiMhNVquNWdtP8cmi/Vy4ZswI3LBUHt5pVY4SgTlMrk7+SUEmiYKMiIj82/XYBEYtP8yPa48Sl2jFxclCz3pFePGRkvh5uppdnqAgk0xBRkRE7ubYxSg+nL+PpfvOAZDL242BzUrTuUYwzhqubSoFmSQKMiIici+rDl7g/d/3cORCFADl8/vyXpvy1CwSYHJl2ZeCTBIFGRERSY34RCsTNxxnxNKDXItJAKB15fwMalGG/P6eJleX/SjIJFGQERGR+3HpeizD/zjA1M0nsdnAw9WJfo1K0LdhMTxcNVw7syjIJFGQERGRtNh9KoIhv+9h87ErABTw9+StlmVpUSFIw7UzgYJMEgUZERFJK5vNxu+7zjB0wT7ORMQAUKdYAO+2Lk/ZfPpMyUgKMkkUZERE5EFFxyUwdtVffLvqCLEJVpws0K12YV5+tBQ5vd3MLi9LUpBJoiAjIiLp5eTlaD5ZuJ/54WcA8PN05eVHS9GtdiFcnJ1Mri5rUZBJoiAjIiLpbcORSwz5fQ/7z14DoHReH95tXY56JXKbXFnWoSCTREFGREQyQkKilV82n+TzPw5wNToegGbl8/J2y3IEB3iZXJ3jU5BJoiAjIiIZ6Wp0HF8uOcikP0+QaLXh5uJE3wbF6Ne4OF5uLmaX57AUZJIoyIiISGY4cPYa78/bw7rDlwAI8vXgjRZlaFslv4Zrp4GCTBIFGRERySw2m43Fe87x0YK9nLx8A4DqhXPyXuvyVCzoZ3J1jkVBJomCjIiIZLaY+ER+WHuUUcsPcyM+EYsFOlcPZmCz0uTxcTe7PIegIJNEQUZERMxyNiKGTxbuY/aO0wD4uLvw4iMl6VmvCG4uGq79XxRkkijIiIiI2bYev8x7c/cSfioCgGJ5vBncqhyNSweaXJn9Su3nt+KgiIhIBqteOIA5oSF82rESuXO48deFKJ4ev5khv+8hPtFqdnkOTUFGREQkEzg5WehcM5jlAxvxTEhRAMavO0b3H/7k0vVYk6tzXAoyIiIimcjXw5V3Wpdj7FPV8HZzZuNfl2kzah27k247yf1RkBERETFB8wr5mB0aQpFcXpy6eoOOY9Yze/sps8tyOAoyIiIiJimZ14c5YfVpXDoPsQlWBkzbwQfz9pKgvplUU5ARERExkZ+nK9/3rElY4xIA/LD2KD1+3MTlqDiTK3MMCjIiIiImc3ayMLBZacZ0q4aXmzPrj1yi9ci16ptJBQUZERERO9GiYj5m9QuhcFLfTKex65mzQ30z/0VBRkRExI6UDvJhbmh9HiqVh5h4Ky9N3cFH89U3czcKMiIiInbGz8uVH3vVpF+j4gB8t+YoPcdv4or6Zm5japAZOnQoNWvWxMfHh8DAQNq1a8eBAwdS7BMTE0NoaCi5cuUiR44cdOzYkXPnzplUsYiISOZwdrLwWvMyfJPUN7Pu8CVaj1rL3tORZpdmV0wNMqtWrSI0NJSNGzeyZMkS4uPjadq0KVFRUcn7/O9//+P3339nxowZrFq1itOnT9OhQwcTqxYREck8jyX1zRQK8OLvKzfoMGYdc3eeNrssu2FXi0ZeuHCBwMBAVq1aRcOGDYmIiCBPnjxMmTKFTp06AbB//37Kli3Lhg0bqFOnzj2PqUUjRUQkK7gaHceLU3ew+uAFAPo2LMZrzUrj4pw1u0QcctHIiAhjmFlAQAAAW7duJT4+niZNmiTvU6ZMGQoVKsSGDRtMqVFERMQM/l5ujO9VkxeS+mbGrf6LXuM3Z/u+GbsJMlarlQEDBhASEkKFChUAOHv2LG5ubvj7+6fYN2/evJw9e/aOx4mNjSUyMjLFQ0REJCtwdrLwevMyjO5aDU9XZ9Yevkib0dm7b8ZugkxoaCi7d+9m6tSpD3ScoUOH4ufnl/wIDg5OpwpFRETsQ8tK+fitXz0KBXhx8rKxTtO8Xdmzb8YugkxYWBjz5s1jxYoVFCxYMPn5oKAg4uLiuHr1aor9z507R1BQ0B2PNWjQICIiIpIfJ0+ezMjSRURETFE2ny9zw0JoUDI3N+ITCZuynaEL95FotZvW10xhapCx2WyEhYUxa9Ysli9fTtGiRVO8Xr16dVxdXVm2bFnycwcOHODEiRPUrVv3jsd0d3fH19c3xUNERCQr8vdyY8LTtXjuoWIAfLvqL3qN38TV6OzTN2PqqKV+/foxZcoU5syZQ+nSpZOf9/Pzw9PTE4AXXniBBQsWMGHCBHx9fenfvz8A69evT9U5NGpJRESyg993nua1mbu4EZ9IoQAvxvWoTpkgx/3cS+3nt6lBxmKx3PH58ePH06tXL8CYEO+VV17hl19+ITY2lmbNmvHNN9/c9dbSvynIiIhIdrH3dCTPTdrCycs38HR1ZvjjlWlZKZ/ZZaWJQwSZzKAgIyIi2cmVqDhenLqdNYcuAvBCo+IMbFoaZ6c7XzywVw45j4yIiIg8mJzexnwzzzU0+mbGrDzC0xM2ExEdb3JlGUNBRkREJItxcXZi0GNl+bpLVTxcnVh98AJtRq/lwNlrZpeW7hRkREREsqg2lfPz6wv1KJjTk+OXomn/zToWhJ8xu6x0pSAjIiKShZXP78fvYfUJKZGL6LhE+k3exqeL9meZ+WYUZERERLK4nN5u/PR0LZ5tYMzX9s3KI/T+KWv0zSjIiIiIZAMuzk681bIcXz1ZBQ9XJ1YeuEDb0Ws5eM6x+2YUZERERLKRtlUKMPP5ehTw9+TYpWjajV7Hot2O2zejICMiIpLNVCjgx+/961OvuNE38/ykbQxffMAh+2YUZERERLKhAG83Jj5Ti971jb6ZUSsO0+enzUTccKy+GQUZERGRbMrF2YnBrcox4okquLs4seLABdqNXschB+qbUZARERHJ5tpVLcCvLxh9M0cvRiX1zZw1u6xUUZARERERKhTwY25YCHWL5SIqLpHnJ23liz8OYLXzvhkFGREREQEgVw53fu5di2dCjL6Zr5cf5tmJW4iMsd++GQUZERERSebi7MQ7rcvxRefKuLs4sWz/edqNWsfh8/bZN6MgIyIiIrfpUK0gM5+vR34/D/66GEW70ev5Y4/99c0oyIiIiMgdVSzox9z+9aldNIDrsQn0/XkrXyw5aFd9MwoyIiIicle5c7gzqU9tetUrAsDXyw7R92f76ZtRkBEREZH/5OrsxHttyvP545Vxc3Fi6b7ztBu9jsPnr5tdmoKMiIiIpE7H6gWZ+Xxd8vl58NcFY76ZJXvPmVqTgoyIiIikWqWC/vzevz61kvpmnp24he/X/GVaPQoyIiIicl9y53BnclLfjLOThfL5/UyrxWKz2eyn9TgDREZG4ufnR0REBL6+vmaXIyIikqUcPn+dEoE50v24qf381hUZERERSbOMCDH3Q0FGREREHJaCjIiIiDgsBRkRERFxWAoyIiIi4rAUZERERMRhKciIiIiIw1KQEREREYelICMiIiIOS0FGREREHJaCjIiIiDgsBRkRERFxWAoyIiIi4rAUZERERMRhuZhdQEaz2WyAsRy4iIiIOIabn9s3P8fvJssHmWvXrgEQHBxsciUiIiJyv65du4afn99dX7fY7hV1HJzVauX06dP4+PhgsVjS7biRkZEEBwdz8uRJfH190+24knb6O7Ev+vuwL/r7sC/6+7g3m83GtWvXyJ8/P05Od++EyfJXZJycnChYsGCGHd/X11c/hHZGfyf2RX8f9kV/H/ZFfx//7b+uxNykZl8RERFxWAoyIiIi4rAUZNLI3d2dd999F3d3d7NLkST6O7Ev+vuwL/r7sC/6+0g/Wb7ZV0RERLIuXZERERERh6UgIyIiIg5LQUZEREQcloKMiIiIOCwFmTQaPXo0RYoUwcPDg9q1a7Np0yazS8qWhg4dSs2aNfHx8SEwMJB27dpx4MABs8uSJJ988gkWi4UBAwaYXUq2durUKZ566ily5cqFp6cnFStWZMuWLWaXlS0lJiYyePBgihYtiqenJ8WLF+eDDz6453pCcncKMmkwbdo0Xn75Zd599122bdtG5cqVadasGefPnze7tGxn1apVhIaGsnHjRpYsWUJ8fDxNmzYlKirK7NKyvc2bN/Ptt99SqVIls0vJ1q5cuUJISAiurq4sXLiQvXv38vnnn5MzZ06zS8uWhg0bxpgxYxg1ahT79u1j2LBhfPrpp4wcOdLs0hyWhl+nQe3atalZsyajRo0CjPWcgoOD6d+/P2+88YbJ1WVvFy5cIDAwkFWrVtGwYUOzy8m2rl+/TrVq1fjmm2/48MMPqVKlCiNGjDC7rGzpjTfeYN26daxZs8bsUgRo1aoVefPm5Ycffkh+rmPHjnh6ejJp0iQTK3NcuiJzn+Li4ti6dStNmjRJfs7JyYkmTZqwYcMGEysTgIiICAACAgJMriR7Cw0NpWXLlin+PxFzzJ07lxo1avD4448TGBhI1apV+e6778wuK9uqV68ey5Yt4+DBgwDs3LmTtWvX0qJFC5Mrc1xZftHI9Hbx4kUSExPJmzdviufz5s3L/v37TapKwLgyNmDAAEJCQqhQoYLZ5WRbU6dOZdu2bWzevNnsUgT466+/GDNmDC+//DJvvvkmmzdv5sUXX8TNzY2ePXuaXV6288YbbxAZGUmZMmVwdnYmMTGRjz76iG7dupldmsNSkJEsIzQ0lN27d7N27VqzS8m2Tp48yUsvvcSSJUvw8PAwuxzBCPg1atTg448/BqBq1ars3r2bsWPHKsiYYPr06UyePJkpU6ZQvnx5duzYwYABA8ifP7/+PtJIQeY+5c6dG2dnZ86dO5fi+XPnzhEUFGRSVRIWFsa8efNYvXo1BQsWNLucbGvr1q2cP3+eatWqJT+XmJjI6tWrGTVqFLGxsTg7O5tYYfaTL18+ypUrl+K5smXL8uuvv5pUUfb26quv8sYbb/Dkk08CULFiRY4fP87QoUMVZNJIPTL3yc3NjerVq7Ns2bLk56xWK8uWLaNu3bomVpY92Ww2wsLCmDVrFsuXL6do0aJml5StPfLII4SHh7Njx47kR40aNejWrRs7duxQiDFBSEjIbVMSHDx4kMKFC5tUUfYWHR2Nk1PKj15nZ2esVqtJFTk+XZFJg5dffpmePXtSo0YNatWqxYgRI4iKiuLpp582u7RsJzQ0lClTpjBnzhx8fHw4e/YsAH5+fnh6eppcXfbj4+NzW3+St7c3uXLlUt+SSf73v/9Rr149Pv74Yzp37symTZsYN24c48aNM7u0bKl169Z89NFHFCpUiPLly7N9+3a++OILnnnmGbNLc1w2SZORI0faChUqZHNzc7PVqlXLtnHjRrNLypaAOz7Gjx9vdmmS5KGHHrK99NJLZpeRrf3++++2ChUq2Nzd3W1lypSxjRs3zuySsq3IyEjbSy+9ZCtUqJDNw8PDVqxYMdtbb71li42NNbs0h6V5ZERERMRhqUdGREREHJaCjIiIiDgsBRkRERFxWAoyIiIi4rAUZERERMRhKciIiIiIw1KQEREREYelICMi2Y7FYmH27NlmlyEi6UBBRkQyVa9evbBYLLc9mjdvbnZpIuKAtNaSiGS65s2bM378+BTPubu7m1SNiDgyXZERkUzn7u5OUFBQikfOnDkB47bPmDFjaNGiBZ6enhQrVoyZM2emeH94eDgPP/wwnp6e5MqVi759+3L9+vUU+/z444+UL18ed3d38uXLR1hYWIrXL168SPv27fHy8qJkyZLMnTs3Y79pEckQCjIiYncGDx5Mx44d2blzJ926dePJJ59k3759AERFRdGsWTNy5szJ5s2bmTFjBkuXLk0RVMaMGUNoaCh9+/YlPDycuXPnUqJEiRTnGDJkCJ07d2bXrl089thjdOvWjcuXL2fq9yki6cDsVStFJHvp2bOnzdnZ2ebt7Z3i8dFHH9lsNmNF8+effz7Fe2rXrm174YUXbDabzTZu3Dhbzpw5bdevX09+ff78+TYnJyfb2bNnbTabzZY/f37bW2+9ddcaANvbb7+d/PX169dtgG3hwoXp9n2KSOZQj4yIZLrGjRszZsyYFM8FBAQkb9etWzfFa3Xr1mXHjh0A7Nu3j8qVK+Pt7Z38ekhICFarlQMHDmCxWDh9+jSPPPLIf9ZQqVKl5G1vb298fX05f/58Wr8lETGJgoyIZDpvb+/bbvWkF09Pz1Tt5+rqmuJri8WC1WrNiJJEJAOpR0ZE7M7GjRtv+7ps2bIAlC1blp07dxIVFZX8+rp163BycqJ06dL4+PhQpEgRli1blqk1i4g5dEVGRDJdbGwsZ8+eTfGci4sLuXPnBmDGjBnUqFGD+vXrM3nyZDZt2sQPP/wAQLdu3Xj33Xfp2bMn7733HhcuXKB///50796dvHnzAvDee+/x/PPPExgYSIsWLbh27Rrr1q2jf//+mfuNikiGU5ARkUy3aNEi8uXLl+K50qVLs3//fsAYUTR16lT69etHvnz5+OWXXyhXrhwAXl5eLF68mJdeeomaNWvi5eVFx44d+eKLL5KP1bNnT2JiYvjyyy8ZOHAguXPnplOnTpn3DYpIprHYbDab2UWIiNxksViYNWsW7dq1M7sUEXEA6pERERERh6UgIyIiIg5LPTIiYld0t1tE7oeuyIiIiIjDUpARERERh6UgIyIiIg5LQUZEREQcloKMiIiIOCwFGREREXFYCjIiIiLisBRkRERExGEpyIiIiIjD+j8+GNTkGijsEAAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "plt.plot(train_losses, label='Training Loss')\n",
    "plt.plot(val_losses, label='Validation Loss')\n",
    "plt.xlabel('Epoch')\n",
    "plt.ylabel('Loss')\n",
    "plt.title('Error Curve')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 46676,
     "status": "ok",
     "timestamp": 1734603078476,
     "user": {
      "displayName": "yuzhen",
      "userId": "05774191734922144334"
     },
     "user_tz": -480
    },
    "id": "_6_8bcE_FZuu",
    "outputId": "073b0ba9-651a-4f9f-daae-70e36211bac2"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Validation MAE: 26.0869\n"
     ]
    }
   ],
   "source": [
    "# 在测试集上运行模型，计算MAE并保存结果\n",
    "model.eval()\n",
    "total_loss = 0.0\n",
    "total_samples = 0\n",
    "with open('pred_result.txt', 'w') as f:\n",
    "    for inputs, labels in val_loader:\n",
    "        inputs = inputs.to(device)\n",
    "        labels = labels.to(device).unsqueeze(1)  # 确保标签是 float32 且形状为 (batch_size, 1)\n",
    "\n",
    "        with torch.no_grad():\n",
    "            outputs = model(inputs)\n",
    "            loss = criterion(outputs, labels)\n",
    "\n",
    "            # 累加损失和样本数\n",
    "            total_loss += loss.item() * inputs.size(0)\n",
    "            total_samples += inputs.size(0)\n",
    "\n",
    "        # 获取预测值并保存到文件\n",
    "        predictions = outputs.cpu().numpy().flatten()\n",
    "        for img_name, pred in zip(val_dataset.data_frame['image_name'], predictions):\n",
    "            f.write(f'{img_name} {pred:.2f}\\n')  # 保存结果，保留两位小数\n",
    "\n",
    "# 计算MAE\n",
    "mae = total_loss / total_samples\n",
    "print(f'Validation MAE: {mae:.4f}')"
   ]
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "colab": {
   "authorship_tag": "ABX9TyPrZ86a0Y9HJywIVWHGu1I2",
   "gpuType": "T4",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "name": "python3"
  },
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
